Changeset 407bc8c in rtems


Ignore:
Timestamp:
Dec 14, 2000, 2:12:19 PM (20 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, 5, master
Children:
cec6bb0
Parents:
40323b5
Message:

2000-12-14 Eric Norum <eric.norum@…>

  • lib/tftpDriver.c: Added write capability.
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • c/src/exec/libnetworking/ChangeLog

    r40323b5 r407bc8c  
     12000-12-14      Eric Norum <eric.norum@usask.ca>
     2
     3        * lib/tftpDriver.c: Added write capability.
     4
    152000-12-08      Joel Sherrill <joel@OARcorp.com>
    26
  • c/src/exec/libnetworking/lib/tftpDriver.c

    r40323b5 r407bc8c  
    11/*
     2 * vim: set expandtab tabstop=4 shiftwidth=4 ai :
     3 *
    24 * Trivial File Transfer Protocol (RFC 1350)
    35 *
     
    1113 *
    1214 *  $Id$
     15 *
    1316 */
    1417
     
    3740 * Range of UDP ports to try
    3841 */
    39 #define UDP_PORT_BASE   3180
     42#define UDP_PORT_BASE        3180
    4043
    4144/*
    4245 * Pathname prefix
    4346 */
    44 #define TFTP_PATHNAME_PREFIX    "/TFTP/"
     47#define TFTP_PATHNAME_PREFIX "/TFTP/"
    4548
    4649/*
    4750 * Default limits
    4851 */
    49 #define PACKET_REPLY_MILLISECONDS       6000
    50 #define OPEN_RETRY_LIMIT        10
    51 #define IO_RETRY_LIMIT          10
     52#define PACKET_REPLY_MILLISECONDS     6000
     53#define OPEN_RETRY_LIMIT              10
     54#define IO_RETRY_LIMIT                10
    5255
    5356/*
    5457 * TFTP opcodes
    5558 */
    56 #define TFTP_OPCODE_RRQ         1
    57 #define TFTP_OPCODE_WRQ         2
    58 #define TFTP_OPCODE_DATA        3
    59 #define TFTP_OPCODE_ACK         4
    60 #define TFTP_OPCODE_ERROR       5
     59#define TFTP_OPCODE_RRQ     1
     60#define TFTP_OPCODE_WRQ     2
     61#define TFTP_OPCODE_DATA    3
     62#define TFTP_OPCODE_ACK     4
     63#define TFTP_OPCODE_ERROR   5
    6164
    6265/*
    6366 * Largest data transfer
    6467 */
    65 #define TFTP_BUFSIZE    512
     68#define TFTP_BUFSIZE        512
    6669
    6770/*
     
    6972 */
    7073union tftpPacket {
    71         /*
    72         * RRQ/WRQ packet
    73         */
    74         struct tftpRWRQ {
    75                 rtems_unsigned16        opcode;
    76                 char                    filename_mode[TFTP_BUFSIZE];
    77         } tftpRWRQ;
    78 
    79         /*
    80         * DATA packet
    81         */
    82         struct tftpDATA {
    83                 rtems_unsigned16        opcode;
    84                 rtems_unsigned16        blocknum;
    85                 rtems_unsigned8         data[TFTP_BUFSIZE];
    86         } tftpDATA;
    87 
    88         /*
    89         * ACK packet
    90         */
    91         struct tftpACK {
    92                 rtems_unsigned16        opcode;
    93                 rtems_unsigned16        blocknum;
    94         } tftpACK;
    95 
    96         /*
    97         * ERROR packet
    98         */
    99         struct tftpERROR {
    100                 rtems_unsigned16        opcode;
    101                 rtems_unsigned16        errorCode;
    102                 char                    errorMessage[TFTP_BUFSIZE];
    103         } tftpERROR;
     74    /*
     75    * RRQ/WRQ packet
     76    */
     77    struct tftpRWRQ {
     78        rtems_unsigned16    opcode;
     79        char                filename_mode[TFTP_BUFSIZE];
     80    } tftpRWRQ;
     81
     82    /*
     83    * DATA packet
     84    */
     85    struct tftpDATA {
     86        rtems_unsigned16    opcode;
     87        rtems_unsigned16    blocknum;
     88        rtems_unsigned8     data[TFTP_BUFSIZE];
     89    } tftpDATA;
     90
     91    /*
     92    * ACK packet
     93    */
     94    struct tftpACK {
     95        rtems_unsigned16    opcode;
     96        rtems_unsigned16    blocknum;
     97    } tftpACK;
     98
     99    /*
     100    * ERROR packet
     101    */
     102    struct tftpERROR {
     103        rtems_unsigned16    opcode;
     104        rtems_unsigned16    errorCode;
     105        char                errorMessage[TFTP_BUFSIZE];
     106    } tftpERROR;
    104107};
    105108
     
    108111 */
    109112struct tftpStream {
    110         /*
    111          * Buffer for storing most recently-received packet
    112          */
    113         union tftpPacket        pkbuf;
    114 
    115         /*
    116          * Last block number received
    117          */
    118         rtems_unsigned16        blocknum;
    119 
    120         /*
    121          * Data transfer socket
    122          */
    123         int                     socket;
    124         struct sockaddr_in      myAddress;
    125         struct sockaddr_in      farAddress;
    126 
    127         /*
    128          * Indices into buffer
    129          */
    130         int     nleft;
    131         int     nused;
    132 
    133         /*
    134          * Flags
    135          */
    136         int     firstReply;
    137         int     eof;
     113    /*
     114     * Buffer for storing most recently-received packet
     115     */
     116    union tftpPacket    pkbuf;
     117
     118    /*
     119     * Last block number transferred
     120     */
     121    rtems_unsigned16    blocknum;
     122
     123    /*
     124     * Data transfer socket
     125     */
     126    int                 socket;
     127    struct sockaddr_in  myAddress;
     128    struct sockaddr_in  farAddress;
     129
     130    /*
     131     * Indices into buffer
     132     */
     133    int     nleft;
     134    int     nused;
     135
     136    /*
     137     * Flags
     138     */
     139    int     firstReply;
     140    int     eof;
     141    int     writing;
    138142};
    139143
     
    169173};
    170174
    171 int rtems_tftp_mount_me(
     175static int rtems_tftp_mount_me(
    172176  rtems_filesystem_mount_table_entry_t *temp_mt_entry
    173177)
     
    225229int rtems_bsdnet_initialize_tftp_filesystem ()
    226230{
    227  int                                   status;
    228  rtems_filesystem_mount_table_entry_t *entry;
    229 
    230  status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
    231  if ( status == -1 )
    232    return status;
    233 
    234   status = mount(
    235      &entry,
    236      &rtems_tftp_ops,
    237      RTEMS_FILESYSTEM_READ_ONLY,
    238      NULL,
    239      TFTP_PATHNAME_PREFIX
    240   );
    241 
    242   if ( status )
    243     perror( "TFTP mount failed" );
    244 
    245   return status;
    246 }
    247 
    248 /*
    249  * Set error message
    250  * This RTEMS/UNIX error mapping needs to be fixed!
    251  */
    252 static void
    253 tftpSetErrno (struct tftpStream *tp)
    254 {
    255         unsigned int tftpError;
    256         static const int errorMap[] = {
    257                 0,
    258                 ENOENT,
    259                 EPERM,
    260                 ENOSPC,
    261                 EINVAL,
    262                 ENXIO,
    263                 EEXIST,
    264                 ESRCH,
    265                 0,
    266         };
    267 
    268         tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
    269         if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
    270                 errno = errorMap[tftpError];
    271         else
    272                 errno = 1000 + tftpError;
     231    int                                   status;
     232    rtems_filesystem_mount_table_entry_t *entry;
     233
     234    status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
     235    if ( status == -1 )
     236        return status;
     237
     238    status = mount(
     239            &entry,
     240            &rtems_tftp_ops,
     241            RTEMS_FILESYSTEM_READ_WRITE,
     242            NULL,
     243            TFTP_PATHNAME_PREFIX
     244    );
     245
     246    if ( status )
     247        perror( "TFTP mount failed" );
     248
     249    return status;
     250}
     251
     252/*
     253 * Map error message
     254 */
     255static int
     256tftpErrno (struct tftpStream *tp)
     257{
     258    unsigned int tftpError;
     259    static const int errorMap[] = {
     260        EINVAL,
     261        ENOENT,
     262        EPERM,
     263        ENOSPC,
     264        EINVAL,
     265        ENXIO,
     266        EEXIST,
     267        ESRCH,
     268    };
     269
     270    tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
     271    if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
     272        return errorMap[tftpError];
     273    else
     274        return 1000 + tftpError;
    273275}
    274276
     
    279281sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
    280282{
    281         int len;
    282 
    283         /*
    284          * Create the error packet (Unknown transfer ID).
    285          */
    286         tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR);
    287         tp->pkbuf.tftpERROR.errorCode = htons (5);
    288         len = sizeof tp->pkbuf.tftpERROR.opcode +
    289                                 sizeof tp->pkbuf.tftpERROR.errorCode + 1;
    290         len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY");
    291 
    292         /*
    293          * Send it
    294          */
    295         sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    296                                         (struct sockaddr *)to, sizeof *to);
     283    int len;
     284    struct {
     285        rtems_unsigned16    opcode;
     286        rtems_unsigned16    errorCode;
     287        char                errorMessage[12];
     288    } msg;
     289
     290    /*
     291     * Create the error packet (Unknown transfer ID).
     292     */
     293    msg.opcode = htons (TFTP_OPCODE_ERROR);
     294    msg.errorCode = htons (5);
     295    len = sizeof msg.opcode + sizeof msg.errorCode + 1;
     296    len += sprintf (msg.errorMessage, "GO AWAY");
     297
     298    /*
     299     * Send it
     300     */
     301    sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
    297302}
    298303
     
    303308getPacket (struct tftpStream *tp)
    304309{
    305         int len;
    306         struct timeval tv;
    307 
    308         tv.tv_sec = PACKET_REPLY_MILLISECONDS / 1000;
    309         tv.tv_usec = (PACKET_REPLY_MILLISECONDS % 1000) * 1000;
    310         setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
    311         for (;;) {
    312                 union {
    313                         struct sockaddr s;
    314                         struct sockaddr_in i;
    315                 } from;
    316                 int fromlen = sizeof from;
    317                 len = recvfrom (tp->socket, (char *)&tp->pkbuf,
    318                                                         sizeof tp->pkbuf, 0,
    319                                                         &from.s, &fromlen);
    320                 if (len < 0)
    321                         break;
    322                 if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
    323                         if (tp->firstReply) {
    324                                 tp->firstReply = 0;
    325                                 tp->farAddress.sin_port = from.i.sin_port;
    326                         }
    327                         if (tp->farAddress.sin_port == from.i.sin_port)
    328                                 break;
    329                 }
    330 
    331                 /*
    332                 * Packet is from someone with whom we are
    333                 * not interested.  Tell them to go away.
    334                 */
    335                 sendStifle (tp, &from.i);
    336         }
    337         tv.tv_sec = 0;
    338         tv.tv_usec = 0;
    339         setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
    340         return len;
     310    int len;
     311    struct timeval tv;
     312
     313    tv.tv_sec = PACKET_REPLY_MILLISECONDS / 1000;
     314    tv.tv_usec = (PACKET_REPLY_MILLISECONDS % 1000) * 1000;
     315    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
     316    for (;;) {
     317        union {
     318            struct sockaddr s;
     319            struct sockaddr_in i;
     320        } from;
     321        int fromlen = sizeof from;
     322        len = recvfrom (tp->socket, (char *)&tp->pkbuf,
     323                                                    sizeof tp->pkbuf, 0,
     324                                                    &from.s, &fromlen);
     325        if (len < 0)
     326            break;
     327        if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
     328            if (tp->firstReply) {
     329                tp->firstReply = 0;
     330                tp->farAddress.sin_port = from.i.sin_port;
     331            }
     332            if (tp->farAddress.sin_port == from.i.sin_port)
     333                break;
     334        }
     335
     336        /*
     337        * Packet is from someone with whom we are
     338        * not interested.  Tell them to go away.
     339        */
     340        sendStifle (tp, &from.i);
     341    }
     342    tv.tv_sec = 0;
     343    tv.tv_usec = 0;
     344    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
     345    return len;
    341346}
    342347
     
    347352sendAck (struct tftpStream *tp)
    348353{
    349         /*
    350         * Create the acknowledgement
    351         */
    352         tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
    353         tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
    354 
    355         /*
    356         * Send it
    357         */
    358         if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
    359                                         (struct sockaddr *)&tp->farAddress,
    360                                         sizeof tp->farAddress) < 0)
    361                 return errno;
    362         return 0;
     354    /*
     355    * Create the acknowledgement
     356    */
     357    tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
     358    tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
     359
     360    /*
     361    * Send it
     362    */
     363    if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
     364                                    (struct sockaddr *)&tp->farAddress,
     365                                    sizeof tp->farAddress) < 0)
     366        return errno;
     367    return 0;
    363368}
    364369
     
    369374releaseStream (int s)
    370375{
    371         rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    372         free (tftpStreams[s]);
    373         tftpStreams[s] = NULL;
    374         rtems_semaphore_release (tftp_mutex);
    375 }
    376 
    377 int rtems_tftp_evaluate_for_make(
     376    rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     377    free (tftpStreams[s]);
     378    tftpStreams[s] = NULL;
     379    rtems_semaphore_release (tftp_mutex);
     380}
     381
     382static int rtems_tftp_evaluate_for_make(
    378383   const char                         *path,       /* IN     */
    379384   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
     
    384389}
    385390
    386 /*
    387  * XXX - Fix return values.
    388  */
    389 
    390 int rtems_tftp_eval_path( 
     391
     392static int rtems_tftp_eval_path( 
    391393  const char                        *pathname,     /* IN     */
    392394  int                                flags,        /* IN     */
     
    395397{
    396398
    397   /*
    398    * Read-only for now
    399    */
    400    
    401   if ( (flags & O_WRONLY) == O_WRONLY )
    402     set_errno_and_return_minus_one( ENOENT );
    403 
    404   /*
    405    * The File system is mounted at TFTP_PATHNAME_PREFIX
    406    * the caller of this routine has striped off this part of the
    407    * name. Save the remainder of the name for use by the open routine.
    408    */
    409 
    410   pathloc->node_access = (void * ) pathname;
    411   pathloc->handlers    = &rtems_tftp_handlers;
    412 
    413   return 0;
    414 }
    415 
    416 
    417 int rtems_tftp_open(
    418   rtems_libio_t *iop,
    419   const char    *new_name,
    420   unsigned32     flag,
    421   unsigned32     mode
     399    /*
     400     * Read-only or write-only for now
     401     */
     402    flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
     403    if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
     404        set_errno_and_return_minus_one( EINVAL );
     405
     406    /*
     407     * The File system is mounted at TFTP_PATHNAME_PREFIX
     408     * the caller of this routine has striped off this part of the
     409     * name. Save the remainder of the name for use by the open routine.
     410     */
     411    pathloc->node_access = (void * ) pathname;
     412    pathloc->handlers    = &rtems_tftp_handlers;
     413    return 0;
     414}
     415
     416static int rtems_tftp_open(
     417    rtems_libio_t *iop,
     418    const char    *new_name,
     419    unsigned32     flags,
     420    unsigned32     mode
    422421)
    423422{
    424   struct tftpStream  *tp;
    425   int                 retryCount;
    426   rtems_unsigned32    farAddress;
    427   int                 s;
    428   int                 len;
    429   char               *cp1;
    430   char               *cp2;
    431   char               *remoteFilename;
    432   rtems_interval      now;
    433   rtems_status_code   sc;
    434   char               *hostname;
    435 
    436   /*
    437    * This came from the evaluate path.
    438    */
    439 
    440   cp2 = iop->file_info; 
    441 
    442   cp1 = cp2;
    443   while (*cp2 != '/') {
     423    struct tftpStream    *tp;
     424    int                  retryCount;
     425    struct in_addr       farAddress;
     426    int                  s;
     427    int                  len;
     428    char                 *cp1;
     429    char                 *cp2;
     430    char                 *remoteFilename;
     431    rtems_interval       now;
     432    rtems_status_code    sc;
     433    char                 *hostname;
     434
     435    /*
     436     * This came from the evaluate path.
     437     * Extract host name component
     438     */
     439    cp1 = cp2 = iop->file_info;   
     440    while (*cp2 != '/') {
     441        if (*cp2 == '\0')
     442            return ENOENT;
     443        cp2++;
     444    }
     445    len = cp2 - cp1;
     446    hostname = malloc (len + 1);
     447    if (hostname == NULL)
     448        return ENOMEM;
     449    strncpy (hostname, cp1, len);
     450    hostname[len] = '\0';
     451
     452    /*
     453     * Convert hostname to Internet address
     454     */
     455    if (strcmp (hostname, "BOOTP_HOST") == 0)
     456        farAddress = rtems_bsdnet_bootp_server_address;
     457    else
     458        farAddress.s_addr = inet_addr (hostname);
     459    free (hostname);
     460    if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))
     461        return ENOENT;
     462
     463    /*
     464     * Extract file pathname component
     465     */
     466    while (*cp2 == '/')
     467        cp2++;
     468    if (strcmp (cp2, "BOOTP_FILE") == 0) {
     469        cp2 = rtems_bsdnet_bootp_boot_file_name;
     470        while (*cp2 == '/')
     471            cp2++;
     472    }
    444473    if (*cp2 == '\0')
    445       return ENOENT;
    446     cp2++;
    447   }
    448 
    449   len = cp2 - cp1;
    450   hostname = malloc (len + 1);
    451   if (hostname == NULL)
    452     return ENOMEM;
    453 
    454   strncpy (hostname, cp1, len);
    455   hostname[len] = '\0';
    456   farAddress = inet_addr (hostname);
    457   free (hostname);
    458 
    459   if ((farAddress == 0) || (farAddress == ~0))
    460     return ENOENT;
    461 
    462   if (*++cp2 == '\0')
    463     return ENOENT;
    464 
    465   remoteFilename = cp2;
    466   if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    467     return ENOENT;   
    468 
    469   /*
    470    * Find a free stream
    471    */
    472 
    473   sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    474   if (sc != RTEMS_SUCCESSFUL)
    475     return EBUSY;
    476 
    477   for (s = 0 ; s < nStreams ; s++) {
    478     if (tftpStreams[s] == NULL)
    479     break;
    480   }
    481 
    482   if (s == nStreams) {
    483     /*
    484      * Reallocate stream pointers
    485      * Guard against the case where realloc() returns NULL.
    486      */
    487     struct tftpStream **np;
    488 
    489     np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    490     if (np == NULL) {
    491       rtems_semaphore_release (tftp_mutex);
    492       return ENOMEM;
    493     }
    494     tftpStreams = np;
    495   }
    496 
    497   tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    498   rtems_semaphore_release (tftp_mutex);
    499   if (tp == NULL)
    500     return ENOMEM;
    501   iop->data0 = s;
    502   iop->data1 = tp;
    503 
    504   /*
    505    * Create the socket
    506    */
    507 
    508   if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    509     releaseStream (s);
    510     return ENOMEM;
    511   }
    512 
    513   /*
    514    * Bind the socket to a local address
    515    */
    516 
    517   retryCount = 0;
    518   rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    519   for (;;) {
    520     int try = (now + retryCount) % 10;
    521 
    522     tp->myAddress.sin_family = AF_INET;
    523     tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);
    524     tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    525     if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    526       break;
    527     if (++retryCount == 10) {
    528       close (tp->socket);
    529       releaseStream (s);
    530       return EBUSY;
    531     }
    532   }
    533 
    534   /*
    535    * Set the UDP destination to the TFTP server
    536    * port on the remote machine.
    537    */
    538   tp->farAddress.sin_family = AF_INET;
    539   tp->farAddress.sin_addr.s_addr = farAddress;
    540   tp->farAddress.sin_port = htons (69);
    541 
    542   /*
    543    * Start the transfer
    544    */
    545   tp->firstReply = 1;
    546   for (;;) {
    547     /*
    548      * Create the request
    549      */
    550     tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    551     cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
    552     cp2 = (char *) remoteFilename;
    553     while ((*cp1++ = *cp2++) != '\0')
    554       continue;
    555     cp2 = "octet";
    556     while ((*cp1++ = *cp2++) != '\0')
    557       continue;
    558     len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    559 
    560     /*
    561      * Send the request
    562      */
    563     if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    564           (struct sockaddr *)&tp->farAddress,
    565           sizeof tp->farAddress) < 0) {
    566       close (tp->socket);
    567       releaseStream (s);
    568       return EIO;
    569     }
    570 
    571     /*
    572      * Get reply
    573      */
    574     len = getPacket (tp);
    575     if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    576       int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    577       if ((opcode == TFTP_OPCODE_DATA)
    578        && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    579         tp->nused = 0;
    580         tp->blocknum = 1;
    581         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    582         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    583         if (sendAck (tp) != 0) {
    584           close (tp->socket);
    585           releaseStream (s);
    586           return EIO;
    587         }
     474        return ENOENT;
     475    remoteFilename = cp2;
     476    if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     477        return ENOENT;       
     478
     479    /*
     480     * Find a free stream
     481     */
     482    sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     483    if (sc != RTEMS_SUCCESSFUL)
     484        return EBUSY;
     485    for (s = 0 ; s < nStreams ; s++) {
     486        if (tftpStreams[s] == NULL)
    588487        break;
    589       }
    590       if (opcode == TFTP_OPCODE_ERROR) {
    591         tftpSetErrno (tp);
    592         close (tp->socket);
     488    }
     489    if (s == nStreams) {
     490        /*
     491         * Reallocate stream pointers
     492         * Guard against the case where realloc() returns NULL.
     493         */
     494        struct tftpStream **np;
     495
     496        np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     497        if (np == NULL) {
     498            rtems_semaphore_release (tftp_mutex);
     499            return ENOMEM;
     500        }
     501        tftpStreams = np;
     502    }
     503    tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     504    rtems_semaphore_release (tftp_mutex);
     505    if (tp == NULL)
     506        return ENOMEM;
     507    iop->data0 = s;
     508    iop->data1 = tp;
     509
     510    /*
     511     * Create the socket
     512     */
     513    if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    593514        releaseStream (s);
     515        return ENOMEM;
     516    }
     517
     518    /*
     519     * Bind the socket to a local address
     520     */
     521    retryCount = 0;
     522    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
     523    for (;;) {
     524        int try = (now + retryCount) % 10;
     525
     526        tp->myAddress.sin_family = AF_INET;
     527        tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);
     528        tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     529        if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     530            break;
     531        if (++retryCount == 10) {
     532            close (tp->socket);
     533            releaseStream (s);
     534            return EBUSY;
     535        }
     536    }
     537
     538    /*
     539     * Set the UDP destination to the TFTP server
     540     * port on the remote machine.
     541     */
     542    tp->farAddress.sin_family = AF_INET;
     543    tp->farAddress.sin_addr = farAddress;
     544    tp->farAddress.sin_port = htons (69);
     545
     546    /*
     547     * Start the transfer
     548     */
     549    tp->firstReply = 1;
     550    for (;;) {
     551        /*
     552         * Create the request
     553         */
     554        if ((flags & O_ACCMODE) == O_RDONLY) {
     555            tp->writing = 0;
     556            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     557        }
     558        else {
     559            tp->writing = 1;
     560            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ);
     561        }
     562        cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     563        cp2 = (char *) remoteFilename;
     564        while ((*cp1++ = *cp2++) != '\0')
     565            continue;
     566        cp2 = "octet";
     567        while ((*cp1++ = *cp2++) != '\0')
     568            continue;
     569        len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     570
     571        /*
     572         * Send the request
     573         */
     574        if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     575                    (struct sockaddr *)&tp->farAddress,
     576                    sizeof tp->farAddress) < 0) {
     577            close (tp->socket);
     578            releaseStream (s);
     579            return EIO;
     580        }
     581
     582        /*
     583         * Get reply
     584         */
     585        len = getPacket (tp);
     586        if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     587            int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     588            if (!tp->writing
     589             && (opcode == TFTP_OPCODE_DATA)
     590             && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     591                tp->nused = 0;
     592                tp->blocknum = 1;
     593                tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     594                tp->eof = (tp->nleft < TFTP_BUFSIZE);
     595                if (sendAck (tp) != 0) {
     596                    close (tp->socket);
     597                    releaseStream (s);
     598                    return EIO;
     599                }
     600                break;
     601            }
     602            if (tp->writing
     603             && (opcode == TFTP_OPCODE_ACK)
     604             && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) {
     605                tp->nused = 0;
     606                tp->blocknum = 1;
     607                break;
     608            }
     609            if (opcode == TFTP_OPCODE_ERROR) {
     610                int e = tftpErrno (tp);
     611                close (tp->socket);
     612                releaseStream (s);
     613                return e;
     614            }
     615        }
     616
     617        /*
     618         * Keep trying
     619         */
     620        if (++retryCount >= OPEN_RETRY_LIMIT) {
     621            close (tp->socket);
     622            releaseStream (s);
     623            return EIO;
     624        }
     625    }
     626    return 0;
     627}
     628
     629/*
     630 * Read from a TFTP stream
     631 */
     632static int rtems_tftp_read(
     633    rtems_libio_t *iop,
     634    void          *buffer,
     635    unsigned32    count
     636)
     637{
     638    char              *bp;
     639    struct tftpStream *tp = iop->data1;
     640    int               retryCount;
     641    int               nwant;
     642
     643
     644    /*
     645     * Read till user request is satisfied or EOF is reached
     646     */
     647    bp = buffer;
     648    nwant = count;
     649    while (nwant) {
     650        if (tp->nleft) {
     651            int ncopy;
     652            if (nwant < tp->nleft)
     653                ncopy = nwant;
     654            else
     655                ncopy = tp->nleft;
     656            memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
     657            tp->nused += ncopy;
     658            tp->nleft -= ncopy;
     659            bp += ncopy;
     660            nwant -= ncopy;
     661            if (nwant == 0)
     662                break;
     663        }
     664        if (tp->eof)
     665            break;
     666
     667        /*
     668         * Wait for the next packet
     669         */
     670        retryCount = 0;
     671        for (;;) {
     672            int len = getPacket (tp);
     673            if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     674                int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     675                rtems_unsigned16 nextBlock = tp->blocknum + 1;
     676                if ((opcode == TFTP_OPCODE_DATA)
     677                 && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     678                    tp->nused = 0;
     679                    tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     680                    tp->eof = (tp->nleft < TFTP_BUFSIZE);
     681                    tp->blocknum++;
     682                    if (sendAck (tp) != 0)
     683                        set_errno_and_return_minus_one( EIO );
     684                    break;
     685                }
     686                if (opcode == TFTP_OPCODE_ERROR)
     687                        set_errno_and_return_minus_one( tftpErrno (tp) );
     688            }
     689
     690            /*
     691             * Keep trying?
     692             */
     693            if (++retryCount == IO_RETRY_LIMIT)
     694                set_errno_and_return_minus_one( EIO );
     695            if (sendAck (tp) != 0)
     696                set_errno_and_return_minus_one( EIO );
     697        }
     698    }
     699    return count - nwant;
     700}
     701
     702/*
     703 * Flush a write buffer and wait for acknowledgement
     704 */
     705static int rtems_tftp_flush ( struct tftpStream *tp )
     706{
     707    int wlen, rlen;
     708    int retryCount = 0;
     709
     710    wlen = tp->nused + 2 * sizeof (rtems_unsigned16);
     711    for (;;) {
     712        tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
     713        tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
     714        if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
     715                                        (struct sockaddr *)&tp->farAddress,
     716                                        sizeof tp->farAddress) < 0)
     717            return EIO;
     718        rlen = getPacket (tp);
     719        if (rlen >= (int)sizeof tp->pkbuf.tftpACK) {
     720            int opcode = ntohs (tp->pkbuf.tftpACK.opcode);
     721            if ((opcode == TFTP_OPCODE_ACK)
     722             && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) {
     723                tp->nused = 0;
     724                tp->blocknum++;
     725                return 0;
     726            }
     727            if (opcode == TFTP_OPCODE_ERROR)
     728                return tftpErrno (tp);
     729        }
     730
     731        /*
     732         * Keep trying?
     733         */
     734        if (++retryCount == IO_RETRY_LIMIT)
     735            return EIO;
     736    }
     737}
     738
     739/*
     740 * Close a TFTP stream
     741 */
     742static int rtems_tftp_close(
     743    rtems_libio_t *iop
     744)
     745{
     746    struct tftpStream *tp = iop->data1;;
     747
     748    if (tp->writing)
     749        rtems_tftp_flush (tp);
     750    if (!tp->eof && !tp->firstReply) {
     751        /*
     752         * Tell the other end to stop
     753         */
     754        rtems_interval ticksPerSecond;
     755        sendStifle (tp, &tp->farAddress);
     756        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     757        rtems_task_wake_after (1 + ticksPerSecond / 10);
     758    }
     759    close (tp->socket);
     760    releaseStream (iop->data0);
     761    return RTEMS_SUCCESSFUL;
     762}
     763
     764static int rtems_tftp_write(
     765    rtems_libio_t   *iop,
     766    const void      *buffer,
     767    unsigned32      count
     768)
     769{
     770    const char        *bp;
     771    struct tftpStream *tp = iop->data1;
     772    int               nleft, nfree, ncopy;
     773
     774    /*
     775     * Bail out if an error has occurred
     776     */
     777    if (!tp->writing)
    594778        return EIO;
    595       }
    596     }
    597 
    598     /*
    599      * Keep trying
    600      */
    601     if (++retryCount >= OPEN_RETRY_LIMIT) {
    602       close (tp->socket);
    603       releaseStream (s);
    604       return EIO;
    605     }
    606   }
    607 
    608   return 0;
    609 }
    610 
    611 /*
    612  * Read from a TFTP stream
    613  */
    614 
    615 int rtems_tftp_read(
    616   rtems_libio_t *iop,
    617   void          *buffer,
    618   unsigned32     count
     779
     780
     781    /*
     782     * Write till user request is satisfied
     783     * Notice that the buffer is flushed as soon as it is filled rather
     784     * than waiting for the next write or a close.  This ensures that
     785     * the flush in close writes a less than full buffer so the far
     786     * end can detect the end-of-file condition.
     787     */
     788    bp = buffer;
     789    nleft = count;
     790    while (nleft) {
     791        nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused;
     792        if (nleft < nfree)
     793            ncopy = nleft;
     794        else
     795            ncopy = nfree;
     796        memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy);
     797        tp->nused += ncopy;
     798        nleft -= ncopy;
     799        bp += ncopy;
     800        if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) {
     801            int e = rtems_tftp_flush (tp);
     802            if (e) {
     803                tp->writing = 0;
     804                set_errno_and_return_minus_one (e);
     805            }
     806        }
     807    }
     808    return count;
     809}
     810
     811/*
     812 * Dummy version to let fopen(xxxx,"w") work properly.
     813 */
     814static int rtems_tftp_ftruncate(
     815    rtems_libio_t   *iop,
     816    off_t           count
    619817)
    620818{
    621   char              *bp;
    622   struct tftpStream *tp;
    623   int                retryCount;
    624   int                nwant;
    625 
    626   tp = iop->data1;
    627 
    628   /*
    629    * Read till user request is satisfied or EOF is reached
    630    */
    631 
    632   bp = buffer;
    633   nwant = count;
    634   while (nwant) {
    635     if (tp->nleft) {
    636       int count;
    637       if (nwant < tp->nleft)
    638         count = nwant;
    639       else
    640         count = tp->nleft;
    641       memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    642       tp->nused += count;
    643       tp->nleft -= count;
    644       bp += count;
    645       nwant -= count;
    646       if (nwant == 0)
    647         break;
    648     }
    649     if (tp->eof)
    650       break;
    651 
    652     /*
    653      * Wait for the next packet
    654      */
    655     retryCount = 0;
    656     for (;;) {
    657       int len = getPacket (tp);
    658       if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    659         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    660         rtems_unsigned16 nextBlock = tp->blocknum + 1;
    661         if ((opcode == TFTP_OPCODE_DATA)
    662          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    663           tp->nused = 0;
    664           tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    665           tp->eof = (tp->nleft < TFTP_BUFSIZE);
    666           tp->blocknum++;
    667           if (sendAck (tp) != 0)
    668             set_errno_and_return_minus_one( EIO );
    669           break;
    670         }
    671         if (opcode == TFTP_OPCODE_ERROR) {
    672           tftpSetErrno (tp);
    673           return RTEMS_INTERNAL_ERROR;
    674         }
    675       }
    676 
    677       /*
    678        * Keep trying?
    679        */
    680       if (++retryCount == IO_RETRY_LIMIT)
    681         set_errno_and_return_minus_one( EIO );
    682       if (sendAck (tp) != 0)
    683         set_errno_and_return_minus_one( EIO );
    684     }
    685   }
    686 
    687  /*
    688   * XXX - Eric is this right?
    689   *
    690   */
    691   return count - nwant;
    692 }
    693 
    694 /*
    695  * Close a TFTP stream
    696  */
    697 int rtems_tftp_close(
    698   rtems_libio_t *iop
     819    return 0;
     820}
     821
     822rtems_filesystem_node_types_t rtems_tftp_node_type(
     823     rtems_filesystem_location_info_t        *pathloc                 /* IN */
    699824)
    700825{
    701   struct tftpStream *tp = iop->data1;;
    702 
    703   if (!tp->eof && !tp->firstReply) {
    704     /*
    705      * Tell the other end to stop
    706      */
    707     rtems_interval ticksPerSecond;
    708     sendStifle (tp, &tp->farAddress);
    709     rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    710     rtems_task_wake_after (1 + ticksPerSecond / 10);
    711   }
    712   close (tp->socket);
    713   releaseStream (iop->data0);
    714   return RTEMS_SUCCESSFUL;
    715 }
    716 
    717 int rtems_tftp_write(
    718   rtems_libio_t *iop,
    719   const void    *buffer,
    720   unsigned32     count
    721 )
    722 {
    723   return RTEMS_NOT_CONFIGURED;
    724 }
    725 
    726 rtems_device_driver rtems_tftp_control(
    727   rtems_device_major_number major,
    728   rtems_device_minor_number minor,
    729   void *pargp
    730 )
    731 {
    732   return RTEMS_NOT_CONFIGURED;
    733 }
    734 
    735 rtems_filesystem_node_types_t rtems_tftp_node_type(
    736    rtems_filesystem_location_info_t    *pathloc         /* IN */
    737 )
    738 {
    739   return RTEMS_FILESYSTEM_MEMORY_FILE;
     826    return RTEMS_FILESYSTEM_MEMORY_FILE;
    740827}
    741828
    742829
    743830rtems_filesystem_operations_table  rtems_tftp_ops = {
    744   rtems_tftp_eval_path,            /* eval_path */
    745   rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
    746   NULL,                            /* link */
    747   NULL,                            /* unlink */
    748   rtems_tftp_node_type,            /* node_type */
    749   NULL,                            /* mknod */
    750   NULL,                            /* chown */
    751   NULL,                            /* freenodinfo */
    752   NULL,                            /* mount */
    753   rtems_tftp_mount_me,             /* initialize */
    754   NULL,                            /* unmount */
    755   NULL,                            /* fsunmount */
    756   NULL,                            /* utime, */
    757   NULL,                            /* evaluate_link */
    758   NULL,                            /* symlink */
    759   NULL,                            /* readlin */
     831    rtems_tftp_eval_path,            /* eval_path */
     832    rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     833    NULL,                            /* link */
     834    NULL,                            /* unlink */
     835    rtems_tftp_node_type,            /* node_type */
     836    NULL,                            /* mknod */
     837    NULL,                            /* chown */
     838    NULL,                            /* freenodinfo */
     839    NULL,                            /* mount */
     840    rtems_tftp_mount_me,             /* initialize */
     841    NULL,                            /* unmount */
     842    NULL,                            /* fsunmount */
     843    NULL,                            /* utime, */
     844    NULL,                            /* evaluate_link */
     845    NULL,                            /* symlink */
     846    NULL,                            /* readlin */
    760847};
    761 
     848 
    762849rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
    763   rtems_tftp_open,   /* open */     
    764   rtems_tftp_close,  /* close */   
    765   rtems_tftp_read,   /* read */     
    766   rtems_tftp_write,  /* write */   
    767   NULL,              /* ioctl */   
    768   NULL,              /* lseek */   
    769   NULL,              /* fstat */   
    770   NULL,              /* fchmod */   
    771   NULL,              /* ftruncate */
    772   NULL,              /* fpathconf */
    773   NULL,              /* fsync */   
    774   NULL,              /* fdatasync */
    775   NULL,              /* fcntl */
    776   NULL               /* rmnod */
     850    rtems_tftp_open,   /* open */     
     851    rtems_tftp_close,  /* close */   
     852    rtems_tftp_read,   /* read */     
     853    rtems_tftp_write,  /* write */   
     854    NULL,              /* ioctl */   
     855    NULL,              /* lseek */   
     856    NULL,              /* fstat */   
     857    NULL,              /* fchmod */   
     858    rtems_tftp_ftruncate, /* ftruncate */
     859    NULL,              /* fpathconf */
     860    NULL,              /* fsync */   
     861    NULL,              /* fdatasync */
     862    NULL,              /* fcntl */
     863    NULL               /* rmnod */
    777864};
  • c/src/libnetworking/ChangeLog

    r40323b5 r407bc8c  
     12000-12-14      Eric Norum <eric.norum@usask.ca>
     2
     3        * lib/tftpDriver.c: Added write capability.
     4
    152000-12-08      Joel Sherrill <joel@OARcorp.com>
    26
  • c/src/libnetworking/lib/tftpDriver.c

    r40323b5 r407bc8c  
    11/*
     2 * vim: set expandtab tabstop=4 shiftwidth=4 ai :
     3 *
    24 * Trivial File Transfer Protocol (RFC 1350)
    35 *
     
    1113 *
    1214 *  $Id$
     15 *
    1316 */
    1417
     
    3740 * Range of UDP ports to try
    3841 */
    39 #define UDP_PORT_BASE   3180
     42#define UDP_PORT_BASE        3180
    4043
    4144/*
    4245 * Pathname prefix
    4346 */
    44 #define TFTP_PATHNAME_PREFIX    "/TFTP/"
     47#define TFTP_PATHNAME_PREFIX "/TFTP/"
    4548
    4649/*
    4750 * Default limits
    4851 */
    49 #define PACKET_REPLY_MILLISECONDS       6000
    50 #define OPEN_RETRY_LIMIT        10
    51 #define IO_RETRY_LIMIT          10
     52#define PACKET_REPLY_MILLISECONDS     6000
     53#define OPEN_RETRY_LIMIT              10
     54#define IO_RETRY_LIMIT                10
    5255
    5356/*
    5457 * TFTP opcodes
    5558 */
    56 #define TFTP_OPCODE_RRQ         1
    57 #define TFTP_OPCODE_WRQ         2
    58 #define TFTP_OPCODE_DATA        3
    59 #define TFTP_OPCODE_ACK         4
    60 #define TFTP_OPCODE_ERROR       5
     59#define TFTP_OPCODE_RRQ     1
     60#define TFTP_OPCODE_WRQ     2
     61#define TFTP_OPCODE_DATA    3
     62#define TFTP_OPCODE_ACK     4
     63#define TFTP_OPCODE_ERROR   5
    6164
    6265/*
    6366 * Largest data transfer
    6467 */
    65 #define TFTP_BUFSIZE    512
     68#define TFTP_BUFSIZE        512
    6669
    6770/*
     
    6972 */
    7073union tftpPacket {
    71         /*
    72         * RRQ/WRQ packet
    73         */
    74         struct tftpRWRQ {
    75                 rtems_unsigned16        opcode;
    76                 char                    filename_mode[TFTP_BUFSIZE];
    77         } tftpRWRQ;
    78 
    79         /*
    80         * DATA packet
    81         */
    82         struct tftpDATA {
    83                 rtems_unsigned16        opcode;
    84                 rtems_unsigned16        blocknum;
    85                 rtems_unsigned8         data[TFTP_BUFSIZE];
    86         } tftpDATA;
    87 
    88         /*
    89         * ACK packet
    90         */
    91         struct tftpACK {
    92                 rtems_unsigned16        opcode;
    93                 rtems_unsigned16        blocknum;
    94         } tftpACK;
    95 
    96         /*
    97         * ERROR packet
    98         */
    99         struct tftpERROR {
    100                 rtems_unsigned16        opcode;
    101                 rtems_unsigned16        errorCode;
    102                 char                    errorMessage[TFTP_BUFSIZE];
    103         } tftpERROR;
     74    /*
     75    * RRQ/WRQ packet
     76    */
     77    struct tftpRWRQ {
     78        rtems_unsigned16    opcode;
     79        char                filename_mode[TFTP_BUFSIZE];
     80    } tftpRWRQ;
     81
     82    /*
     83    * DATA packet
     84    */
     85    struct tftpDATA {
     86        rtems_unsigned16    opcode;
     87        rtems_unsigned16    blocknum;
     88        rtems_unsigned8     data[TFTP_BUFSIZE];
     89    } tftpDATA;
     90
     91    /*
     92    * ACK packet
     93    */
     94    struct tftpACK {
     95        rtems_unsigned16    opcode;
     96        rtems_unsigned16    blocknum;
     97    } tftpACK;
     98
     99    /*
     100    * ERROR packet
     101    */
     102    struct tftpERROR {
     103        rtems_unsigned16    opcode;
     104        rtems_unsigned16    errorCode;
     105        char                errorMessage[TFTP_BUFSIZE];
     106    } tftpERROR;
    104107};
    105108
     
    108111 */
    109112struct tftpStream {
    110         /*
    111          * Buffer for storing most recently-received packet
    112          */
    113         union tftpPacket        pkbuf;
    114 
    115         /*
    116          * Last block number received
    117          */
    118         rtems_unsigned16        blocknum;
    119 
    120         /*
    121          * Data transfer socket
    122          */
    123         int                     socket;
    124         struct sockaddr_in      myAddress;
    125         struct sockaddr_in      farAddress;
    126 
    127         /*
    128          * Indices into buffer
    129          */
    130         int     nleft;
    131         int     nused;
    132 
    133         /*
    134          * Flags
    135          */
    136         int     firstReply;
    137         int     eof;
     113    /*
     114     * Buffer for storing most recently-received packet
     115     */
     116    union tftpPacket    pkbuf;
     117
     118    /*
     119     * Last block number transferred
     120     */
     121    rtems_unsigned16    blocknum;
     122
     123    /*
     124     * Data transfer socket
     125     */
     126    int                 socket;
     127    struct sockaddr_in  myAddress;
     128    struct sockaddr_in  farAddress;
     129
     130    /*
     131     * Indices into buffer
     132     */
     133    int     nleft;
     134    int     nused;
     135
     136    /*
     137     * Flags
     138     */
     139    int     firstReply;
     140    int     eof;
     141    int     writing;
    138142};
    139143
     
    169173};
    170174
    171 int rtems_tftp_mount_me(
     175static int rtems_tftp_mount_me(
    172176  rtems_filesystem_mount_table_entry_t *temp_mt_entry
    173177)
     
    225229int rtems_bsdnet_initialize_tftp_filesystem ()
    226230{
    227  int                                   status;
    228  rtems_filesystem_mount_table_entry_t *entry;
    229 
    230  status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
    231  if ( status == -1 )
    232    return status;
    233 
    234   status = mount(
    235      &entry,
    236      &rtems_tftp_ops,
    237      RTEMS_FILESYSTEM_READ_ONLY,
    238      NULL,
    239      TFTP_PATHNAME_PREFIX
    240   );
    241 
    242   if ( status )
    243     perror( "TFTP mount failed" );
    244 
    245   return status;
    246 }
    247 
    248 /*
    249  * Set error message
    250  * This RTEMS/UNIX error mapping needs to be fixed!
    251  */
    252 static void
    253 tftpSetErrno (struct tftpStream *tp)
    254 {
    255         unsigned int tftpError;
    256         static const int errorMap[] = {
    257                 0,
    258                 ENOENT,
    259                 EPERM,
    260                 ENOSPC,
    261                 EINVAL,
    262                 ENXIO,
    263                 EEXIST,
    264                 ESRCH,
    265                 0,
    266         };
    267 
    268         tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
    269         if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
    270                 errno = errorMap[tftpError];
    271         else
    272                 errno = 1000 + tftpError;
     231    int                                   status;
     232    rtems_filesystem_mount_table_entry_t *entry;
     233
     234    status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
     235    if ( status == -1 )
     236        return status;
     237
     238    status = mount(
     239            &entry,
     240            &rtems_tftp_ops,
     241            RTEMS_FILESYSTEM_READ_WRITE,
     242            NULL,
     243            TFTP_PATHNAME_PREFIX
     244    );
     245
     246    if ( status )
     247        perror( "TFTP mount failed" );
     248
     249    return status;
     250}
     251
     252/*
     253 * Map error message
     254 */
     255static int
     256tftpErrno (struct tftpStream *tp)
     257{
     258    unsigned int tftpError;
     259    static const int errorMap[] = {
     260        EINVAL,
     261        ENOENT,
     262        EPERM,
     263        ENOSPC,
     264        EINVAL,
     265        ENXIO,
     266        EEXIST,
     267        ESRCH,
     268    };
     269
     270    tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
     271    if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
     272        return errorMap[tftpError];
     273    else
     274        return 1000 + tftpError;
    273275}
    274276
     
    279281sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
    280282{
    281         int len;
    282 
    283         /*
    284          * Create the error packet (Unknown transfer ID).
    285          */
    286         tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR);
    287         tp->pkbuf.tftpERROR.errorCode = htons (5);
    288         len = sizeof tp->pkbuf.tftpERROR.opcode +
    289                                 sizeof tp->pkbuf.tftpERROR.errorCode + 1;
    290         len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY");
    291 
    292         /*
    293          * Send it
    294          */
    295         sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    296                                         (struct sockaddr *)to, sizeof *to);
     283    int len;
     284    struct {
     285        rtems_unsigned16    opcode;
     286        rtems_unsigned16    errorCode;
     287        char                errorMessage[12];
     288    } msg;
     289
     290    /*
     291     * Create the error packet (Unknown transfer ID).
     292     */
     293    msg.opcode = htons (TFTP_OPCODE_ERROR);
     294    msg.errorCode = htons (5);
     295    len = sizeof msg.opcode + sizeof msg.errorCode + 1;
     296    len += sprintf (msg.errorMessage, "GO AWAY");
     297
     298    /*
     299     * Send it
     300     */
     301    sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
    297302}
    298303
     
    303308getPacket (struct tftpStream *tp)
    304309{
    305         int len;
    306         struct timeval tv;
    307 
    308         tv.tv_sec = PACKET_REPLY_MILLISECONDS / 1000;
    309         tv.tv_usec = (PACKET_REPLY_MILLISECONDS % 1000) * 1000;
    310         setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
    311         for (;;) {
    312                 union {
    313                         struct sockaddr s;
    314                         struct sockaddr_in i;
    315                 } from;
    316                 int fromlen = sizeof from;
    317                 len = recvfrom (tp->socket, (char *)&tp->pkbuf,
    318                                                         sizeof tp->pkbuf, 0,
    319                                                         &from.s, &fromlen);
    320                 if (len < 0)
    321                         break;
    322                 if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
    323                         if (tp->firstReply) {
    324                                 tp->firstReply = 0;
    325                                 tp->farAddress.sin_port = from.i.sin_port;
    326                         }
    327                         if (tp->farAddress.sin_port == from.i.sin_port)
    328                                 break;
    329                 }
    330 
    331                 /*
    332                 * Packet is from someone with whom we are
    333                 * not interested.  Tell them to go away.
    334                 */
    335                 sendStifle (tp, &from.i);
    336         }
    337         tv.tv_sec = 0;
    338         tv.tv_usec = 0;
    339         setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
    340         return len;
     310    int len;
     311    struct timeval tv;
     312
     313    tv.tv_sec = PACKET_REPLY_MILLISECONDS / 1000;
     314    tv.tv_usec = (PACKET_REPLY_MILLISECONDS % 1000) * 1000;
     315    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
     316    for (;;) {
     317        union {
     318            struct sockaddr s;
     319            struct sockaddr_in i;
     320        } from;
     321        int fromlen = sizeof from;
     322        len = recvfrom (tp->socket, (char *)&tp->pkbuf,
     323                                                    sizeof tp->pkbuf, 0,
     324                                                    &from.s, &fromlen);
     325        if (len < 0)
     326            break;
     327        if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
     328            if (tp->firstReply) {
     329                tp->firstReply = 0;
     330                tp->farAddress.sin_port = from.i.sin_port;
     331            }
     332            if (tp->farAddress.sin_port == from.i.sin_port)
     333                break;
     334        }
     335
     336        /*
     337        * Packet is from someone with whom we are
     338        * not interested.  Tell them to go away.
     339        */
     340        sendStifle (tp, &from.i);
     341    }
     342    tv.tv_sec = 0;
     343    tv.tv_usec = 0;
     344    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
     345    return len;
    341346}
    342347
     
    347352sendAck (struct tftpStream *tp)
    348353{
    349         /*
    350         * Create the acknowledgement
    351         */
    352         tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
    353         tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
    354 
    355         /*
    356         * Send it
    357         */
    358         if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
    359                                         (struct sockaddr *)&tp->farAddress,
    360                                         sizeof tp->farAddress) < 0)
    361                 return errno;
    362         return 0;
     354    /*
     355    * Create the acknowledgement
     356    */
     357    tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
     358    tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
     359
     360    /*
     361    * Send it
     362    */
     363    if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
     364                                    (struct sockaddr *)&tp->farAddress,
     365                                    sizeof tp->farAddress) < 0)
     366        return errno;
     367    return 0;
    363368}
    364369
     
    369374releaseStream (int s)
    370375{
    371         rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    372         free (tftpStreams[s]);
    373         tftpStreams[s] = NULL;
    374         rtems_semaphore_release (tftp_mutex);
    375 }
    376 
    377 int rtems_tftp_evaluate_for_make(
     376    rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     377    free (tftpStreams[s]);
     378    tftpStreams[s] = NULL;
     379    rtems_semaphore_release (tftp_mutex);
     380}
     381
     382static int rtems_tftp_evaluate_for_make(
    378383   const char                         *path,       /* IN     */
    379384   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
     
    384389}
    385390
    386 /*
    387  * XXX - Fix return values.
    388  */
    389 
    390 int rtems_tftp_eval_path( 
     391
     392static int rtems_tftp_eval_path( 
    391393  const char                        *pathname,     /* IN     */
    392394  int                                flags,        /* IN     */
     
    395397{
    396398
    397   /*
    398    * Read-only for now
    399    */
    400    
    401   if ( (flags & O_WRONLY) == O_WRONLY )
    402     set_errno_and_return_minus_one( ENOENT );
    403 
    404   /*
    405    * The File system is mounted at TFTP_PATHNAME_PREFIX
    406    * the caller of this routine has striped off this part of the
    407    * name. Save the remainder of the name for use by the open routine.
    408    */
    409 
    410   pathloc->node_access = (void * ) pathname;
    411   pathloc->handlers    = &rtems_tftp_handlers;
    412 
    413   return 0;
    414 }
    415 
    416 
    417 int rtems_tftp_open(
    418   rtems_libio_t *iop,
    419   const char    *new_name,
    420   unsigned32     flag,
    421   unsigned32     mode
     399    /*
     400     * Read-only or write-only for now
     401     */
     402    flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
     403    if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
     404        set_errno_and_return_minus_one( EINVAL );
     405
     406    /*
     407     * The File system is mounted at TFTP_PATHNAME_PREFIX
     408     * the caller of this routine has striped off this part of the
     409     * name. Save the remainder of the name for use by the open routine.
     410     */
     411    pathloc->node_access = (void * ) pathname;
     412    pathloc->handlers    = &rtems_tftp_handlers;
     413    return 0;
     414}
     415
     416static int rtems_tftp_open(
     417    rtems_libio_t *iop,
     418    const char    *new_name,
     419    unsigned32     flags,
     420    unsigned32     mode
    422421)
    423422{
    424   struct tftpStream  *tp;
    425   int                 retryCount;
    426   rtems_unsigned32    farAddress;
    427   int                 s;
    428   int                 len;
    429   char               *cp1;
    430   char               *cp2;
    431   char               *remoteFilename;
    432   rtems_interval      now;
    433   rtems_status_code   sc;
    434   char               *hostname;
    435 
    436   /*
    437    * This came from the evaluate path.
    438    */
    439 
    440   cp2 = iop->file_info; 
    441 
    442   cp1 = cp2;
    443   while (*cp2 != '/') {
     423    struct tftpStream    *tp;
     424    int                  retryCount;
     425    struct in_addr       farAddress;
     426    int                  s;
     427    int                  len;
     428    char                 *cp1;
     429    char                 *cp2;
     430    char                 *remoteFilename;
     431    rtems_interval       now;
     432    rtems_status_code    sc;
     433    char                 *hostname;
     434
     435    /*
     436     * This came from the evaluate path.
     437     * Extract host name component
     438     */
     439    cp1 = cp2 = iop->file_info;   
     440    while (*cp2 != '/') {
     441        if (*cp2 == '\0')
     442            return ENOENT;
     443        cp2++;
     444    }
     445    len = cp2 - cp1;
     446    hostname = malloc (len + 1);
     447    if (hostname == NULL)
     448        return ENOMEM;
     449    strncpy (hostname, cp1, len);
     450    hostname[len] = '\0';
     451
     452    /*
     453     * Convert hostname to Internet address
     454     */
     455    if (strcmp (hostname, "BOOTP_HOST") == 0)
     456        farAddress = rtems_bsdnet_bootp_server_address;
     457    else
     458        farAddress.s_addr = inet_addr (hostname);
     459    free (hostname);
     460    if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))
     461        return ENOENT;
     462
     463    /*
     464     * Extract file pathname component
     465     */
     466    while (*cp2 == '/')
     467        cp2++;
     468    if (strcmp (cp2, "BOOTP_FILE") == 0) {
     469        cp2 = rtems_bsdnet_bootp_boot_file_name;
     470        while (*cp2 == '/')
     471            cp2++;
     472    }
    444473    if (*cp2 == '\0')
    445       return ENOENT;
    446     cp2++;
    447   }
    448 
    449   len = cp2 - cp1;
    450   hostname = malloc (len + 1);
    451   if (hostname == NULL)
    452     return ENOMEM;
    453 
    454   strncpy (hostname, cp1, len);
    455   hostname[len] = '\0';
    456   farAddress = inet_addr (hostname);
    457   free (hostname);
    458 
    459   if ((farAddress == 0) || (farAddress == ~0))
    460     return ENOENT;
    461 
    462   if (*++cp2 == '\0')
    463     return ENOENT;
    464 
    465   remoteFilename = cp2;
    466   if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    467     return ENOENT;   
    468 
    469   /*
    470    * Find a free stream
    471    */
    472 
    473   sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    474   if (sc != RTEMS_SUCCESSFUL)
    475     return EBUSY;
    476 
    477   for (s = 0 ; s < nStreams ; s++) {
    478     if (tftpStreams[s] == NULL)
    479     break;
    480   }
    481 
    482   if (s == nStreams) {
    483     /*
    484      * Reallocate stream pointers
    485      * Guard against the case where realloc() returns NULL.
    486      */
    487     struct tftpStream **np;
    488 
    489     np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    490     if (np == NULL) {
    491       rtems_semaphore_release (tftp_mutex);
    492       return ENOMEM;
    493     }
    494     tftpStreams = np;
    495   }
    496 
    497   tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    498   rtems_semaphore_release (tftp_mutex);
    499   if (tp == NULL)
    500     return ENOMEM;
    501   iop->data0 = s;
    502   iop->data1 = tp;
    503 
    504   /*
    505    * Create the socket
    506    */
    507 
    508   if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    509     releaseStream (s);
    510     return ENOMEM;
    511   }
    512 
    513   /*
    514    * Bind the socket to a local address
    515    */
    516 
    517   retryCount = 0;
    518   rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    519   for (;;) {
    520     int try = (now + retryCount) % 10;
    521 
    522     tp->myAddress.sin_family = AF_INET;
    523     tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);
    524     tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    525     if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    526       break;
    527     if (++retryCount == 10) {
    528       close (tp->socket);
    529       releaseStream (s);
    530       return EBUSY;
    531     }
    532   }
    533 
    534   /*
    535    * Set the UDP destination to the TFTP server
    536    * port on the remote machine.
    537    */
    538   tp->farAddress.sin_family = AF_INET;
    539   tp->farAddress.sin_addr.s_addr = farAddress;
    540   tp->farAddress.sin_port = htons (69);
    541 
    542   /*
    543    * Start the transfer
    544    */
    545   tp->firstReply = 1;
    546   for (;;) {
    547     /*
    548      * Create the request
    549      */
    550     tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    551     cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
    552     cp2 = (char *) remoteFilename;
    553     while ((*cp1++ = *cp2++) != '\0')
    554       continue;
    555     cp2 = "octet";
    556     while ((*cp1++ = *cp2++) != '\0')
    557       continue;
    558     len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    559 
    560     /*
    561      * Send the request
    562      */
    563     if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    564           (struct sockaddr *)&tp->farAddress,
    565           sizeof tp->farAddress) < 0) {
    566       close (tp->socket);
    567       releaseStream (s);
    568       return EIO;
    569     }
    570 
    571     /*
    572      * Get reply
    573      */
    574     len = getPacket (tp);
    575     if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    576       int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    577       if ((opcode == TFTP_OPCODE_DATA)
    578        && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    579         tp->nused = 0;
    580         tp->blocknum = 1;
    581         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    582         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    583         if (sendAck (tp) != 0) {
    584           close (tp->socket);
    585           releaseStream (s);
    586           return EIO;
    587         }
     474        return ENOENT;
     475    remoteFilename = cp2;
     476    if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     477        return ENOENT;       
     478
     479    /*
     480     * Find a free stream
     481     */
     482    sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     483    if (sc != RTEMS_SUCCESSFUL)
     484        return EBUSY;
     485    for (s = 0 ; s < nStreams ; s++) {
     486        if (tftpStreams[s] == NULL)
    588487        break;
    589       }
    590       if (opcode == TFTP_OPCODE_ERROR) {
    591         tftpSetErrno (tp);
    592         close (tp->socket);
     488    }
     489    if (s == nStreams) {
     490        /*
     491         * Reallocate stream pointers
     492         * Guard against the case where realloc() returns NULL.
     493         */
     494        struct tftpStream **np;
     495
     496        np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     497        if (np == NULL) {
     498            rtems_semaphore_release (tftp_mutex);
     499            return ENOMEM;
     500        }
     501        tftpStreams = np;
     502    }
     503    tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     504    rtems_semaphore_release (tftp_mutex);
     505    if (tp == NULL)
     506        return ENOMEM;
     507    iop->data0 = s;
     508    iop->data1 = tp;
     509
     510    /*
     511     * Create the socket
     512     */
     513    if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    593514        releaseStream (s);
     515        return ENOMEM;
     516    }
     517
     518    /*
     519     * Bind the socket to a local address
     520     */
     521    retryCount = 0;
     522    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
     523    for (;;) {
     524        int try = (now + retryCount) % 10;
     525
     526        tp->myAddress.sin_family = AF_INET;
     527        tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);
     528        tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     529        if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     530            break;
     531        if (++retryCount == 10) {
     532            close (tp->socket);
     533            releaseStream (s);
     534            return EBUSY;
     535        }
     536    }
     537
     538    /*
     539     * Set the UDP destination to the TFTP server
     540     * port on the remote machine.
     541     */
     542    tp->farAddress.sin_family = AF_INET;
     543    tp->farAddress.sin_addr = farAddress;
     544    tp->farAddress.sin_port = htons (69);
     545
     546    /*
     547     * Start the transfer
     548     */
     549    tp->firstReply = 1;
     550    for (;;) {
     551        /*
     552         * Create the request
     553         */
     554        if ((flags & O_ACCMODE) == O_RDONLY) {
     555            tp->writing = 0;
     556            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     557        }
     558        else {
     559            tp->writing = 1;
     560            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ);
     561        }
     562        cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     563        cp2 = (char *) remoteFilename;
     564        while ((*cp1++ = *cp2++) != '\0')
     565            continue;
     566        cp2 = "octet";
     567        while ((*cp1++ = *cp2++) != '\0')
     568            continue;
     569        len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     570
     571        /*
     572         * Send the request
     573         */
     574        if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     575                    (struct sockaddr *)&tp->farAddress,
     576                    sizeof tp->farAddress) < 0) {
     577            close (tp->socket);
     578            releaseStream (s);
     579            return EIO;
     580        }
     581
     582        /*
     583         * Get reply
     584         */
     585        len = getPacket (tp);
     586        if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     587            int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     588            if (!tp->writing
     589             && (opcode == TFTP_OPCODE_DATA)
     590             && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     591                tp->nused = 0;
     592                tp->blocknum = 1;
     593                tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     594                tp->eof = (tp->nleft < TFTP_BUFSIZE);
     595                if (sendAck (tp) != 0) {
     596                    close (tp->socket);
     597                    releaseStream (s);
     598                    return EIO;
     599                }
     600                break;
     601            }
     602            if (tp->writing
     603             && (opcode == TFTP_OPCODE_ACK)
     604             && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) {
     605                tp->nused = 0;
     606                tp->blocknum = 1;
     607                break;
     608            }
     609            if (opcode == TFTP_OPCODE_ERROR) {
     610                int e = tftpErrno (tp);
     611                close (tp->socket);
     612                releaseStream (s);
     613                return e;
     614            }
     615        }
     616
     617        /*
     618         * Keep trying
     619         */
     620        if (++retryCount >= OPEN_RETRY_LIMIT) {
     621            close (tp->socket);
     622            releaseStream (s);
     623            return EIO;
     624        }
     625    }
     626    return 0;
     627}
     628
     629/*
     630 * Read from a TFTP stream
     631 */
     632static int rtems_tftp_read(
     633    rtems_libio_t *iop,
     634    void          *buffer,
     635    unsigned32    count
     636)
     637{
     638    char              *bp;
     639    struct tftpStream *tp = iop->data1;
     640    int               retryCount;
     641    int               nwant;
     642
     643
     644    /*
     645     * Read till user request is satisfied or EOF is reached
     646     */
     647    bp = buffer;
     648    nwant = count;
     649    while (nwant) {
     650        if (tp->nleft) {
     651            int ncopy;
     652            if (nwant < tp->nleft)
     653                ncopy = nwant;
     654            else
     655                ncopy = tp->nleft;
     656            memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
     657            tp->nused += ncopy;
     658            tp->nleft -= ncopy;
     659            bp += ncopy;
     660            nwant -= ncopy;
     661            if (nwant == 0)
     662                break;
     663        }
     664        if (tp->eof)
     665            break;
     666
     667        /*
     668         * Wait for the next packet
     669         */
     670        retryCount = 0;
     671        for (;;) {
     672            int len = getPacket (tp);
     673            if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     674                int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     675                rtems_unsigned16 nextBlock = tp->blocknum + 1;
     676                if ((opcode == TFTP_OPCODE_DATA)
     677                 && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     678                    tp->nused = 0;
     679                    tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     680                    tp->eof = (tp->nleft < TFTP_BUFSIZE);
     681                    tp->blocknum++;
     682                    if (sendAck (tp) != 0)
     683                        set_errno_and_return_minus_one( EIO );
     684                    break;
     685                }
     686                if (opcode == TFTP_OPCODE_ERROR)
     687                        set_errno_and_return_minus_one( tftpErrno (tp) );
     688            }
     689
     690            /*
     691             * Keep trying?
     692             */
     693            if (++retryCount == IO_RETRY_LIMIT)
     694                set_errno_and_return_minus_one( EIO );
     695            if (sendAck (tp) != 0)
     696                set_errno_and_return_minus_one( EIO );
     697        }
     698    }
     699    return count - nwant;
     700}
     701
     702/*
     703 * Flush a write buffer and wait for acknowledgement
     704 */
     705static int rtems_tftp_flush ( struct tftpStream *tp )
     706{
     707    int wlen, rlen;
     708    int retryCount = 0;
     709
     710    wlen = tp->nused + 2 * sizeof (rtems_unsigned16);
     711    for (;;) {
     712        tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
     713        tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
     714        if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
     715                                        (struct sockaddr *)&tp->farAddress,
     716                                        sizeof tp->farAddress) < 0)
     717            return EIO;
     718        rlen = getPacket (tp);
     719        if (rlen >= (int)sizeof tp->pkbuf.tftpACK) {
     720            int opcode = ntohs (tp->pkbuf.tftpACK.opcode);
     721            if ((opcode == TFTP_OPCODE_ACK)
     722             && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) {
     723                tp->nused = 0;
     724                tp->blocknum++;
     725                return 0;
     726            }
     727            if (opcode == TFTP_OPCODE_ERROR)
     728                return tftpErrno (tp);
     729        }
     730
     731        /*
     732         * Keep trying?
     733         */
     734        if (++retryCount == IO_RETRY_LIMIT)
     735            return EIO;
     736    }
     737}
     738
     739/*
     740 * Close a TFTP stream
     741 */
     742static int rtems_tftp_close(
     743    rtems_libio_t *iop
     744)
     745{
     746    struct tftpStream *tp = iop->data1;;
     747
     748    if (tp->writing)
     749        rtems_tftp_flush (tp);
     750    if (!tp->eof && !tp->firstReply) {
     751        /*
     752         * Tell the other end to stop
     753         */
     754        rtems_interval ticksPerSecond;
     755        sendStifle (tp, &tp->farAddress);
     756        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     757        rtems_task_wake_after (1 + ticksPerSecond / 10);
     758    }
     759    close (tp->socket);
     760    releaseStream (iop->data0);
     761    return RTEMS_SUCCESSFUL;
     762}
     763
     764static int rtems_tftp_write(
     765    rtems_libio_t   *iop,
     766    const void      *buffer,
     767    unsigned32      count
     768)
     769{
     770    const char        *bp;
     771    struct tftpStream *tp = iop->data1;
     772    int               nleft, nfree, ncopy;
     773
     774    /*
     775     * Bail out if an error has occurred
     776     */
     777    if (!tp->writing)
    594778        return EIO;
    595       }
    596     }
    597 
    598     /*
    599      * Keep trying
    600      */
    601     if (++retryCount >= OPEN_RETRY_LIMIT) {
    602       close (tp->socket);
    603       releaseStream (s);
    604       return EIO;
    605     }
    606   }
    607 
    608   return 0;
    609 }
    610 
    611 /*
    612  * Read from a TFTP stream
    613  */
    614 
    615 int rtems_tftp_read(
    616   rtems_libio_t *iop,
    617   void          *buffer,
    618   unsigned32     count
     779
     780
     781    /*
     782     * Write till user request is satisfied
     783     * Notice that the buffer is flushed as soon as it is filled rather
     784     * than waiting for the next write or a close.  This ensures that
     785     * the flush in close writes a less than full buffer so the far
     786     * end can detect the end-of-file condition.
     787     */
     788    bp = buffer;
     789    nleft = count;
     790    while (nleft) {
     791        nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused;
     792        if (nleft < nfree)
     793            ncopy = nleft;
     794        else
     795            ncopy = nfree;
     796        memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy);
     797        tp->nused += ncopy;
     798        nleft -= ncopy;
     799        bp += ncopy;
     800        if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) {
     801            int e = rtems_tftp_flush (tp);
     802            if (e) {
     803                tp->writing = 0;
     804                set_errno_and_return_minus_one (e);
     805            }
     806        }
     807    }
     808    return count;
     809}
     810
     811/*
     812 * Dummy version to let fopen(xxxx,"w") work properly.
     813 */
     814static int rtems_tftp_ftruncate(
     815    rtems_libio_t   *iop,
     816    off_t           count
    619817)
    620818{
    621   char              *bp;
    622   struct tftpStream *tp;
    623   int                retryCount;
    624   int                nwant;
    625 
    626   tp = iop->data1;
    627 
    628   /*
    629    * Read till user request is satisfied or EOF is reached
    630    */
    631 
    632   bp = buffer;
    633   nwant = count;
    634   while (nwant) {
    635     if (tp->nleft) {
    636       int count;
    637       if (nwant < tp->nleft)
    638         count = nwant;
    639       else
    640         count = tp->nleft;
    641       memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    642       tp->nused += count;
    643       tp->nleft -= count;
    644       bp += count;
    645       nwant -= count;
    646       if (nwant == 0)
    647         break;
    648     }
    649     if (tp->eof)
    650       break;
    651 
    652     /*
    653      * Wait for the next packet
    654      */
    655     retryCount = 0;
    656     for (;;) {
    657       int len = getPacket (tp);
    658       if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    659         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    660         rtems_unsigned16 nextBlock = tp->blocknum + 1;
    661         if ((opcode == TFTP_OPCODE_DATA)
    662          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    663           tp->nused = 0;
    664           tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    665           tp->eof = (tp->nleft < TFTP_BUFSIZE);
    666           tp->blocknum++;
    667           if (sendAck (tp) != 0)
    668             set_errno_and_return_minus_one( EIO );
    669           break;
    670         }
    671         if (opcode == TFTP_OPCODE_ERROR) {
    672           tftpSetErrno (tp);
    673           return RTEMS_INTERNAL_ERROR;
    674         }
    675       }
    676 
    677       /*
    678        * Keep trying?
    679        */
    680       if (++retryCount == IO_RETRY_LIMIT)
    681         set_errno_and_return_minus_one( EIO );
    682       if (sendAck (tp) != 0)
    683         set_errno_and_return_minus_one( EIO );
    684     }
    685   }
    686 
    687  /*
    688   * XXX - Eric is this right?
    689   *
    690   */
    691   return count - nwant;
    692 }
    693 
    694 /*
    695  * Close a TFTP stream
    696  */
    697 int rtems_tftp_close(
    698   rtems_libio_t *iop
     819    return 0;
     820}
     821
     822rtems_filesystem_node_types_t rtems_tftp_node_type(
     823     rtems_filesystem_location_info_t        *pathloc                 /* IN */
    699824)
    700825{
    701   struct tftpStream *tp = iop->data1;;
    702 
    703   if (!tp->eof && !tp->firstReply) {
    704     /*
    705      * Tell the other end to stop
    706      */
    707     rtems_interval ticksPerSecond;
    708     sendStifle (tp, &tp->farAddress);
    709     rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    710     rtems_task_wake_after (1 + ticksPerSecond / 10);
    711   }
    712   close (tp->socket);
    713   releaseStream (iop->data0);
    714   return RTEMS_SUCCESSFUL;
    715 }
    716 
    717 int rtems_tftp_write(
    718   rtems_libio_t *iop,
    719   const void    *buffer,
    720   unsigned32     count
    721 )
    722 {
    723   return RTEMS_NOT_CONFIGURED;
    724 }
    725 
    726 rtems_device_driver rtems_tftp_control(
    727   rtems_device_major_number major,
    728   rtems_device_minor_number minor,
    729   void *pargp
    730 )
    731 {
    732   return RTEMS_NOT_CONFIGURED;
    733 }
    734 
    735 rtems_filesystem_node_types_t rtems_tftp_node_type(
    736    rtems_filesystem_location_info_t    *pathloc         /* IN */
    737 )
    738 {
    739   return RTEMS_FILESYSTEM_MEMORY_FILE;
     826    return RTEMS_FILESYSTEM_MEMORY_FILE;
    740827}
    741828
    742829
    743830rtems_filesystem_operations_table  rtems_tftp_ops = {
    744   rtems_tftp_eval_path,            /* eval_path */
    745   rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
    746   NULL,                            /* link */
    747   NULL,                            /* unlink */
    748   rtems_tftp_node_type,            /* node_type */
    749   NULL,                            /* mknod */
    750   NULL,                            /* chown */
    751   NULL,                            /* freenodinfo */
    752   NULL,                            /* mount */
    753   rtems_tftp_mount_me,             /* initialize */
    754   NULL,                            /* unmount */
    755   NULL,                            /* fsunmount */
    756   NULL,                            /* utime, */
    757   NULL,                            /* evaluate_link */
    758   NULL,                            /* symlink */
    759   NULL,                            /* readlin */
     831    rtems_tftp_eval_path,            /* eval_path */
     832    rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     833    NULL,                            /* link */
     834    NULL,                            /* unlink */
     835    rtems_tftp_node_type,            /* node_type */
     836    NULL,                            /* mknod */
     837    NULL,                            /* chown */
     838    NULL,                            /* freenodinfo */
     839    NULL,                            /* mount */
     840    rtems_tftp_mount_me,             /* initialize */
     841    NULL,                            /* unmount */
     842    NULL,                            /* fsunmount */
     843    NULL,                            /* utime, */
     844    NULL,                            /* evaluate_link */
     845    NULL,                            /* symlink */
     846    NULL,                            /* readlin */
    760847};
    761 
     848 
    762849rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
    763   rtems_tftp_open,   /* open */     
    764   rtems_tftp_close,  /* close */   
    765   rtems_tftp_read,   /* read */     
    766   rtems_tftp_write,  /* write */   
    767   NULL,              /* ioctl */   
    768   NULL,              /* lseek */   
    769   NULL,              /* fstat */   
    770   NULL,              /* fchmod */   
    771   NULL,              /* ftruncate */
    772   NULL,              /* fpathconf */
    773   NULL,              /* fsync */   
    774   NULL,              /* fdatasync */
    775   NULL,              /* fcntl */
    776   NULL               /* rmnod */
     850    rtems_tftp_open,   /* open */     
     851    rtems_tftp_close,  /* close */   
     852    rtems_tftp_read,   /* read */     
     853    rtems_tftp_write,  /* write */   
     854    NULL,              /* ioctl */   
     855    NULL,              /* lseek */   
     856    NULL,              /* fstat */   
     857    NULL,              /* fchmod */   
     858    rtems_tftp_ftruncate, /* ftruncate */
     859    NULL,              /* fpathconf */
     860    NULL,              /* fsync */   
     861    NULL,              /* fdatasync */
     862    NULL,              /* fcntl */
     863    NULL               /* rmnod */
    777864};
  • cpukit/libnetworking/ChangeLog

    r40323b5 r407bc8c  
     12000-12-14      Eric Norum <eric.norum@usask.ca>
     2
     3        * lib/tftpDriver.c: Added write capability.
     4
    152000-12-08      Joel Sherrill <joel@OARcorp.com>
    26
  • cpukit/libnetworking/lib/tftpDriver.c

    r40323b5 r407bc8c  
    11/*
     2 * vim: set expandtab tabstop=4 shiftwidth=4 ai :
     3 *
    24 * Trivial File Transfer Protocol (RFC 1350)
    35 *
     
    1113 *
    1214 *  $Id$
     15 *
    1316 */
    1417
     
    3740 * Range of UDP ports to try
    3841 */
    39 #define UDP_PORT_BASE   3180
     42#define UDP_PORT_BASE        3180
    4043
    4144/*
    4245 * Pathname prefix
    4346 */
    44 #define TFTP_PATHNAME_PREFIX    "/TFTP/"
     47#define TFTP_PATHNAME_PREFIX "/TFTP/"
    4548
    4649/*
    4750 * Default limits
    4851 */
    49 #define PACKET_REPLY_MILLISECONDS       6000
    50 #define OPEN_RETRY_LIMIT        10
    51 #define IO_RETRY_LIMIT          10
     52#define PACKET_REPLY_MILLISECONDS     6000
     53#define OPEN_RETRY_LIMIT              10
     54#define IO_RETRY_LIMIT                10
    5255
    5356/*
    5457 * TFTP opcodes
    5558 */
    56 #define TFTP_OPCODE_RRQ         1
    57 #define TFTP_OPCODE_WRQ         2
    58 #define TFTP_OPCODE_DATA        3
    59 #define TFTP_OPCODE_ACK         4
    60 #define TFTP_OPCODE_ERROR       5
     59#define TFTP_OPCODE_RRQ     1
     60#define TFTP_OPCODE_WRQ     2
     61#define TFTP_OPCODE_DATA    3
     62#define TFTP_OPCODE_ACK     4
     63#define TFTP_OPCODE_ERROR   5
    6164
    6265/*
    6366 * Largest data transfer
    6467 */
    65 #define TFTP_BUFSIZE    512
     68#define TFTP_BUFSIZE        512
    6669
    6770/*
     
    6972 */
    7073union tftpPacket {
    71         /*
    72         * RRQ/WRQ packet
    73         */
    74         struct tftpRWRQ {
    75                 rtems_unsigned16        opcode;
    76                 char                    filename_mode[TFTP_BUFSIZE];
    77         } tftpRWRQ;
    78 
    79         /*
    80         * DATA packet
    81         */
    82         struct tftpDATA {
    83                 rtems_unsigned16        opcode;
    84                 rtems_unsigned16        blocknum;
    85                 rtems_unsigned8         data[TFTP_BUFSIZE];
    86         } tftpDATA;
    87 
    88         /*
    89         * ACK packet
    90         */
    91         struct tftpACK {
    92                 rtems_unsigned16        opcode;
    93                 rtems_unsigned16        blocknum;
    94         } tftpACK;
    95 
    96         /*
    97         * ERROR packet
    98         */
    99         struct tftpERROR {
    100                 rtems_unsigned16        opcode;
    101                 rtems_unsigned16        errorCode;
    102                 char                    errorMessage[TFTP_BUFSIZE];
    103         } tftpERROR;
     74    /*
     75    * RRQ/WRQ packet
     76    */
     77    struct tftpRWRQ {
     78        rtems_unsigned16    opcode;
     79        char                filename_mode[TFTP_BUFSIZE];
     80    } tftpRWRQ;
     81
     82    /*
     83    * DATA packet
     84    */
     85    struct tftpDATA {
     86        rtems_unsigned16    opcode;
     87        rtems_unsigned16    blocknum;
     88        rtems_unsigned8     data[TFTP_BUFSIZE];
     89    } tftpDATA;
     90
     91    /*
     92    * ACK packet
     93    */
     94    struct tftpACK {
     95        rtems_unsigned16    opcode;
     96        rtems_unsigned16    blocknum;
     97    } tftpACK;
     98
     99    /*
     100    * ERROR packet
     101    */
     102    struct tftpERROR {
     103        rtems_unsigned16    opcode;
     104        rtems_unsigned16    errorCode;
     105        char                errorMessage[TFTP_BUFSIZE];
     106    } tftpERROR;
    104107};
    105108
     
    108111 */
    109112struct tftpStream {
    110         /*
    111          * Buffer for storing most recently-received packet
    112          */
    113         union tftpPacket        pkbuf;
    114 
    115         /*
    116          * Last block number received
    117          */
    118         rtems_unsigned16        blocknum;
    119 
    120         /*
    121          * Data transfer socket
    122          */
    123         int                     socket;
    124         struct sockaddr_in      myAddress;
    125         struct sockaddr_in      farAddress;
    126 
    127         /*
    128          * Indices into buffer
    129          */
    130         int     nleft;
    131         int     nused;
    132 
    133         /*
    134          * Flags
    135          */
    136         int     firstReply;
    137         int     eof;
     113    /*
     114     * Buffer for storing most recently-received packet
     115     */
     116    union tftpPacket    pkbuf;
     117
     118    /*
     119     * Last block number transferred
     120     */
     121    rtems_unsigned16    blocknum;
     122
     123    /*
     124     * Data transfer socket
     125     */
     126    int                 socket;
     127    struct sockaddr_in  myAddress;
     128    struct sockaddr_in  farAddress;
     129
     130    /*
     131     * Indices into buffer
     132     */
     133    int     nleft;
     134    int     nused;
     135
     136    /*
     137     * Flags
     138     */
     139    int     firstReply;
     140    int     eof;
     141    int     writing;
    138142};
    139143
     
    169173};
    170174
    171 int rtems_tftp_mount_me(
     175static int rtems_tftp_mount_me(
    172176  rtems_filesystem_mount_table_entry_t *temp_mt_entry
    173177)
     
    225229int rtems_bsdnet_initialize_tftp_filesystem ()
    226230{
    227  int                                   status;
    228  rtems_filesystem_mount_table_entry_t *entry;
    229 
    230  status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
    231  if ( status == -1 )
    232    return status;
    233 
    234   status = mount(
    235      &entry,
    236      &rtems_tftp_ops,
    237      RTEMS_FILESYSTEM_READ_ONLY,
    238      NULL,
    239      TFTP_PATHNAME_PREFIX
    240   );
    241 
    242   if ( status )
    243     perror( "TFTP mount failed" );
    244 
    245   return status;
    246 }
    247 
    248 /*
    249  * Set error message
    250  * This RTEMS/UNIX error mapping needs to be fixed!
    251  */
    252 static void
    253 tftpSetErrno (struct tftpStream *tp)
    254 {
    255         unsigned int tftpError;
    256         static const int errorMap[] = {
    257                 0,
    258                 ENOENT,
    259                 EPERM,
    260                 ENOSPC,
    261                 EINVAL,
    262                 ENXIO,
    263                 EEXIST,
    264                 ESRCH,
    265                 0,
    266         };
    267 
    268         tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
    269         if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
    270                 errno = errorMap[tftpError];
    271         else
    272                 errno = 1000 + tftpError;
     231    int                                   status;
     232    rtems_filesystem_mount_table_entry_t *entry;
     233
     234    status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
     235    if ( status == -1 )
     236        return status;
     237
     238    status = mount(
     239            &entry,
     240            &rtems_tftp_ops,
     241            RTEMS_FILESYSTEM_READ_WRITE,
     242            NULL,
     243            TFTP_PATHNAME_PREFIX
     244    );
     245
     246    if ( status )
     247        perror( "TFTP mount failed" );
     248
     249    return status;
     250}
     251
     252/*
     253 * Map error message
     254 */
     255static int
     256tftpErrno (struct tftpStream *tp)
     257{
     258    unsigned int tftpError;
     259    static const int errorMap[] = {
     260        EINVAL,
     261        ENOENT,
     262        EPERM,
     263        ENOSPC,
     264        EINVAL,
     265        ENXIO,
     266        EEXIST,
     267        ESRCH,
     268    };
     269
     270    tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
     271    if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
     272        return errorMap[tftpError];
     273    else
     274        return 1000 + tftpError;
    273275}
    274276
     
    279281sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
    280282{
    281         int len;
    282 
    283         /*
    284          * Create the error packet (Unknown transfer ID).
    285          */
    286         tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR);
    287         tp->pkbuf.tftpERROR.errorCode = htons (5);
    288         len = sizeof tp->pkbuf.tftpERROR.opcode +
    289                                 sizeof tp->pkbuf.tftpERROR.errorCode + 1;
    290         len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY");
    291 
    292         /*
    293          * Send it
    294          */
    295         sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    296                                         (struct sockaddr *)to, sizeof *to);
     283    int len;
     284    struct {
     285        rtems_unsigned16    opcode;
     286        rtems_unsigned16    errorCode;
     287        char                errorMessage[12];
     288    } msg;
     289
     290    /*
     291     * Create the error packet (Unknown transfer ID).
     292     */
     293    msg.opcode = htons (TFTP_OPCODE_ERROR);
     294    msg.errorCode = htons (5);
     295    len = sizeof msg.opcode + sizeof msg.errorCode + 1;
     296    len += sprintf (msg.errorMessage, "GO AWAY");
     297
     298    /*
     299     * Send it
     300     */
     301    sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
    297302}
    298303
     
    303308getPacket (struct tftpStream *tp)
    304309{
    305         int len;
    306         struct timeval tv;
    307 
    308         tv.tv_sec = PACKET_REPLY_MILLISECONDS / 1000;
    309         tv.tv_usec = (PACKET_REPLY_MILLISECONDS % 1000) * 1000;
    310         setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
    311         for (;;) {
    312                 union {
    313                         struct sockaddr s;
    314                         struct sockaddr_in i;
    315                 } from;
    316                 int fromlen = sizeof from;
    317                 len = recvfrom (tp->socket, (char *)&tp->pkbuf,
    318                                                         sizeof tp->pkbuf, 0,
    319                                                         &from.s, &fromlen);
    320                 if (len < 0)
    321                         break;
    322                 if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
    323                         if (tp->firstReply) {
    324                                 tp->firstReply = 0;
    325                                 tp->farAddress.sin_port = from.i.sin_port;
    326                         }
    327                         if (tp->farAddress.sin_port == from.i.sin_port)
    328                                 break;
    329                 }
    330 
    331                 /*
    332                 * Packet is from someone with whom we are
    333                 * not interested.  Tell them to go away.
    334                 */
    335                 sendStifle (tp, &from.i);
    336         }
    337         tv.tv_sec = 0;
    338         tv.tv_usec = 0;
    339         setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
    340         return len;
     310    int len;
     311    struct timeval tv;
     312
     313    tv.tv_sec = PACKET_REPLY_MILLISECONDS / 1000;
     314    tv.tv_usec = (PACKET_REPLY_MILLISECONDS % 1000) * 1000;
     315    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
     316    for (;;) {
     317        union {
     318            struct sockaddr s;
     319            struct sockaddr_in i;
     320        } from;
     321        int fromlen = sizeof from;
     322        len = recvfrom (tp->socket, (char *)&tp->pkbuf,
     323                                                    sizeof tp->pkbuf, 0,
     324                                                    &from.s, &fromlen);
     325        if (len < 0)
     326            break;
     327        if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
     328            if (tp->firstReply) {
     329                tp->firstReply = 0;
     330                tp->farAddress.sin_port = from.i.sin_port;
     331            }
     332            if (tp->farAddress.sin_port == from.i.sin_port)
     333                break;
     334        }
     335
     336        /*
     337        * Packet is from someone with whom we are
     338        * not interested.  Tell them to go away.
     339        */
     340        sendStifle (tp, &from.i);
     341    }
     342    tv.tv_sec = 0;
     343    tv.tv_usec = 0;
     344    setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
     345    return len;
    341346}
    342347
     
    347352sendAck (struct tftpStream *tp)
    348353{
    349         /*
    350         * Create the acknowledgement
    351         */
    352         tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
    353         tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
    354 
    355         /*
    356         * Send it
    357         */
    358         if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
    359                                         (struct sockaddr *)&tp->farAddress,
    360                                         sizeof tp->farAddress) < 0)
    361                 return errno;
    362         return 0;
     354    /*
     355    * Create the acknowledgement
     356    */
     357    tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
     358    tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
     359
     360    /*
     361    * Send it
     362    */
     363    if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
     364                                    (struct sockaddr *)&tp->farAddress,
     365                                    sizeof tp->farAddress) < 0)
     366        return errno;
     367    return 0;
    363368}
    364369
     
    369374releaseStream (int s)
    370375{
    371         rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    372         free (tftpStreams[s]);
    373         tftpStreams[s] = NULL;
    374         rtems_semaphore_release (tftp_mutex);
    375 }
    376 
    377 int rtems_tftp_evaluate_for_make(
     376    rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     377    free (tftpStreams[s]);
     378    tftpStreams[s] = NULL;
     379    rtems_semaphore_release (tftp_mutex);
     380}
     381
     382static int rtems_tftp_evaluate_for_make(
    378383   const char                         *path,       /* IN     */
    379384   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
     
    384389}
    385390
    386 /*
    387  * XXX - Fix return values.
    388  */
    389 
    390 int rtems_tftp_eval_path( 
     391
     392static int rtems_tftp_eval_path( 
    391393  const char                        *pathname,     /* IN     */
    392394  int                                flags,        /* IN     */
     
    395397{
    396398
    397   /*
    398    * Read-only for now
    399    */
    400    
    401   if ( (flags & O_WRONLY) == O_WRONLY )
    402     set_errno_and_return_minus_one( ENOENT );
    403 
    404   /*
    405    * The File system is mounted at TFTP_PATHNAME_PREFIX
    406    * the caller of this routine has striped off this part of the
    407    * name. Save the remainder of the name for use by the open routine.
    408    */
    409 
    410   pathloc->node_access = (void * ) pathname;
    411   pathloc->handlers    = &rtems_tftp_handlers;
    412 
    413   return 0;
    414 }
    415 
    416 
    417 int rtems_tftp_open(
    418   rtems_libio_t *iop,
    419   const char    *new_name,
    420   unsigned32     flag,
    421   unsigned32     mode
     399    /*
     400     * Read-only or write-only for now
     401     */
     402    flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
     403    if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
     404        set_errno_and_return_minus_one( EINVAL );
     405
     406    /*
     407     * The File system is mounted at TFTP_PATHNAME_PREFIX
     408     * the caller of this routine has striped off this part of the
     409     * name. Save the remainder of the name for use by the open routine.
     410     */
     411    pathloc->node_access = (void * ) pathname;
     412    pathloc->handlers    = &rtems_tftp_handlers;
     413    return 0;
     414}
     415
     416static int rtems_tftp_open(
     417    rtems_libio_t *iop,
     418    const char    *new_name,
     419    unsigned32     flags,
     420    unsigned32     mode
    422421)
    423422{
    424   struct tftpStream  *tp;
    425   int                 retryCount;
    426   rtems_unsigned32    farAddress;
    427   int                 s;
    428   int                 len;
    429   char               *cp1;
    430   char               *cp2;
    431   char               *remoteFilename;
    432   rtems_interval      now;
    433   rtems_status_code   sc;
    434   char               *hostname;
    435 
    436   /*
    437    * This came from the evaluate path.
    438    */
    439 
    440   cp2 = iop->file_info; 
    441 
    442   cp1 = cp2;
    443   while (*cp2 != '/') {
     423    struct tftpStream    *tp;
     424    int                  retryCount;
     425    struct in_addr       farAddress;
     426    int                  s;
     427    int                  len;
     428    char                 *cp1;
     429    char                 *cp2;
     430    char                 *remoteFilename;
     431    rtems_interval       now;
     432    rtems_status_code    sc;
     433    char                 *hostname;
     434
     435    /*
     436     * This came from the evaluate path.
     437     * Extract host name component
     438     */
     439    cp1 = cp2 = iop->file_info;   
     440    while (*cp2 != '/') {
     441        if (*cp2 == '\0')
     442            return ENOENT;
     443        cp2++;
     444    }
     445    len = cp2 - cp1;
     446    hostname = malloc (len + 1);
     447    if (hostname == NULL)
     448        return ENOMEM;
     449    strncpy (hostname, cp1, len);
     450    hostname[len] = '\0';
     451
     452    /*
     453     * Convert hostname to Internet address
     454     */
     455    if (strcmp (hostname, "BOOTP_HOST") == 0)
     456        farAddress = rtems_bsdnet_bootp_server_address;
     457    else
     458        farAddress.s_addr = inet_addr (hostname);
     459    free (hostname);
     460    if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))
     461        return ENOENT;
     462
     463    /*
     464     * Extract file pathname component
     465     */
     466    while (*cp2 == '/')
     467        cp2++;
     468    if (strcmp (cp2, "BOOTP_FILE") == 0) {
     469        cp2 = rtems_bsdnet_bootp_boot_file_name;
     470        while (*cp2 == '/')
     471            cp2++;
     472    }
    444473    if (*cp2 == '\0')
    445       return ENOENT;
    446     cp2++;
    447   }
    448 
    449   len = cp2 - cp1;
    450   hostname = malloc (len + 1);
    451   if (hostname == NULL)
    452     return ENOMEM;
    453 
    454   strncpy (hostname, cp1, len);
    455   hostname[len] = '\0';
    456   farAddress = inet_addr (hostname);
    457   free (hostname);
    458 
    459   if ((farAddress == 0) || (farAddress == ~0))
    460     return ENOENT;
    461 
    462   if (*++cp2 == '\0')
    463     return ENOENT;
    464 
    465   remoteFilename = cp2;
    466   if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    467     return ENOENT;   
    468 
    469   /*
    470    * Find a free stream
    471    */
    472 
    473   sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    474   if (sc != RTEMS_SUCCESSFUL)
    475     return EBUSY;
    476 
    477   for (s = 0 ; s < nStreams ; s++) {
    478     if (tftpStreams[s] == NULL)
    479     break;
    480   }
    481 
    482   if (s == nStreams) {
    483     /*
    484      * Reallocate stream pointers
    485      * Guard against the case where realloc() returns NULL.
    486      */
    487     struct tftpStream **np;
    488 
    489     np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    490     if (np == NULL) {
    491       rtems_semaphore_release (tftp_mutex);
    492       return ENOMEM;
    493     }
    494     tftpStreams = np;
    495   }
    496 
    497   tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    498   rtems_semaphore_release (tftp_mutex);
    499   if (tp == NULL)
    500     return ENOMEM;
    501   iop->data0 = s;
    502   iop->data1 = tp;
    503 
    504   /*
    505    * Create the socket
    506    */
    507 
    508   if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    509     releaseStream (s);
    510     return ENOMEM;
    511   }
    512 
    513   /*
    514    * Bind the socket to a local address
    515    */
    516 
    517   retryCount = 0;
    518   rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    519   for (;;) {
    520     int try = (now + retryCount) % 10;
    521 
    522     tp->myAddress.sin_family = AF_INET;
    523     tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);
    524     tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    525     if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    526       break;
    527     if (++retryCount == 10) {
    528       close (tp->socket);
    529       releaseStream (s);
    530       return EBUSY;
    531     }
    532   }
    533 
    534   /*
    535    * Set the UDP destination to the TFTP server
    536    * port on the remote machine.
    537    */
    538   tp->farAddress.sin_family = AF_INET;
    539   tp->farAddress.sin_addr.s_addr = farAddress;
    540   tp->farAddress.sin_port = htons (69);
    541 
    542   /*
    543    * Start the transfer
    544    */
    545   tp->firstReply = 1;
    546   for (;;) {
    547     /*
    548      * Create the request
    549      */
    550     tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    551     cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
    552     cp2 = (char *) remoteFilename;
    553     while ((*cp1++ = *cp2++) != '\0')
    554       continue;
    555     cp2 = "octet";
    556     while ((*cp1++ = *cp2++) != '\0')
    557       continue;
    558     len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    559 
    560     /*
    561      * Send the request
    562      */
    563     if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    564           (struct sockaddr *)&tp->farAddress,
    565           sizeof tp->farAddress) < 0) {
    566       close (tp->socket);
    567       releaseStream (s);
    568       return EIO;
    569     }
    570 
    571     /*
    572      * Get reply
    573      */
    574     len = getPacket (tp);
    575     if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    576       int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    577       if ((opcode == TFTP_OPCODE_DATA)
    578        && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    579         tp->nused = 0;
    580         tp->blocknum = 1;
    581         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    582         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    583         if (sendAck (tp) != 0) {
    584           close (tp->socket);
    585           releaseStream (s);
    586           return EIO;
    587         }
     474        return ENOENT;
     475    remoteFilename = cp2;
     476    if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     477        return ENOENT;       
     478
     479    /*
     480     * Find a free stream
     481     */
     482    sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     483    if (sc != RTEMS_SUCCESSFUL)
     484        return EBUSY;
     485    for (s = 0 ; s < nStreams ; s++) {
     486        if (tftpStreams[s] == NULL)
    588487        break;
    589       }
    590       if (opcode == TFTP_OPCODE_ERROR) {
    591         tftpSetErrno (tp);
    592         close (tp->socket);
     488    }
     489    if (s == nStreams) {
     490        /*
     491         * Reallocate stream pointers
     492         * Guard against the case where realloc() returns NULL.
     493         */
     494        struct tftpStream **np;
     495
     496        np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     497        if (np == NULL) {
     498            rtems_semaphore_release (tftp_mutex);
     499            return ENOMEM;
     500        }
     501        tftpStreams = np;
     502    }
     503    tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     504    rtems_semaphore_release (tftp_mutex);
     505    if (tp == NULL)
     506        return ENOMEM;
     507    iop->data0 = s;
     508    iop->data1 = tp;
     509
     510    /*
     511     * Create the socket
     512     */
     513    if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    593514        releaseStream (s);
     515        return ENOMEM;
     516    }
     517
     518    /*
     519     * Bind the socket to a local address
     520     */
     521    retryCount = 0;
     522    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
     523    for (;;) {
     524        int try = (now + retryCount) % 10;
     525
     526        tp->myAddress.sin_family = AF_INET;
     527        tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + s);
     528        tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     529        if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     530            break;
     531        if (++retryCount == 10) {
     532            close (tp->socket);
     533            releaseStream (s);
     534            return EBUSY;
     535        }
     536    }
     537
     538    /*
     539     * Set the UDP destination to the TFTP server
     540     * port on the remote machine.
     541     */
     542    tp->farAddress.sin_family = AF_INET;
     543    tp->farAddress.sin_addr = farAddress;
     544    tp->farAddress.sin_port = htons (69);
     545
     546    /*
     547     * Start the transfer
     548     */
     549    tp->firstReply = 1;
     550    for (;;) {
     551        /*
     552         * Create the request
     553         */
     554        if ((flags & O_ACCMODE) == O_RDONLY) {
     555            tp->writing = 0;
     556            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     557        }
     558        else {
     559            tp->writing = 1;
     560            tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ);
     561        }
     562        cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     563        cp2 = (char *) remoteFilename;
     564        while ((*cp1++ = *cp2++) != '\0')
     565            continue;
     566        cp2 = "octet";
     567        while ((*cp1++ = *cp2++) != '\0')
     568            continue;
     569        len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     570
     571        /*
     572         * Send the request
     573         */
     574        if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     575                    (struct sockaddr *)&tp->farAddress,
     576                    sizeof tp->farAddress) < 0) {
     577            close (tp->socket);
     578            releaseStream (s);
     579            return EIO;
     580        }
     581
     582        /*
     583         * Get reply
     584         */
     585        len = getPacket (tp);
     586        if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     587            int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     588            if (!tp->writing
     589             && (opcode == TFTP_OPCODE_DATA)
     590             && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     591                tp->nused = 0;
     592                tp->blocknum = 1;
     593                tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     594                tp->eof = (tp->nleft < TFTP_BUFSIZE);
     595                if (sendAck (tp) != 0) {
     596                    close (tp->socket);
     597                    releaseStream (s);
     598                    return EIO;
     599                }
     600                break;
     601            }
     602            if (tp->writing
     603             && (opcode == TFTP_OPCODE_ACK)
     604             && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) {
     605                tp->nused = 0;
     606                tp->blocknum = 1;
     607                break;
     608            }
     609            if (opcode == TFTP_OPCODE_ERROR) {
     610                int e = tftpErrno (tp);
     611                close (tp->socket);
     612                releaseStream (s);
     613                return e;
     614            }
     615        }
     616
     617        /*
     618         * Keep trying
     619         */
     620        if (++retryCount >= OPEN_RETRY_LIMIT) {
     621            close (tp->socket);
     622            releaseStream (s);
     623            return EIO;
     624        }
     625    }
     626    return 0;
     627}
     628
     629/*
     630 * Read from a TFTP stream
     631 */
     632static int rtems_tftp_read(
     633    rtems_libio_t *iop,
     634    void          *buffer,
     635    unsigned32    count
     636)
     637{
     638    char              *bp;
     639    struct tftpStream *tp = iop->data1;
     640    int               retryCount;
     641    int               nwant;
     642
     643
     644    /*
     645     * Read till user request is satisfied or EOF is reached
     646     */
     647    bp = buffer;
     648    nwant = count;
     649    while (nwant) {
     650        if (tp->nleft) {
     651            int ncopy;
     652            if (nwant < tp->nleft)
     653                ncopy = nwant;
     654            else
     655                ncopy = tp->nleft;
     656            memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
     657            tp->nused += ncopy;
     658            tp->nleft -= ncopy;
     659            bp += ncopy;
     660            nwant -= ncopy;
     661            if (nwant == 0)
     662                break;
     663        }
     664        if (tp->eof)
     665            break;
     666
     667        /*
     668         * Wait for the next packet
     669         */
     670        retryCount = 0;
     671        for (;;) {
     672            int len = getPacket (tp);
     673            if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     674                int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     675                rtems_unsigned16 nextBlock = tp->blocknum + 1;
     676                if ((opcode == TFTP_OPCODE_DATA)
     677                 && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     678                    tp->nused = 0;
     679                    tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     680                    tp->eof = (tp->nleft < TFTP_BUFSIZE);
     681                    tp->blocknum++;
     682                    if (sendAck (tp) != 0)
     683                        set_errno_and_return_minus_one( EIO );
     684                    break;
     685                }
     686                if (opcode == TFTP_OPCODE_ERROR)
     687                        set_errno_and_return_minus_one( tftpErrno (tp) );
     688            }
     689
     690            /*
     691             * Keep trying?
     692             */
     693            if (++retryCount == IO_RETRY_LIMIT)
     694                set_errno_and_return_minus_one( EIO );
     695            if (sendAck (tp) != 0)
     696                set_errno_and_return_minus_one( EIO );
     697        }
     698    }
     699    return count - nwant;
     700}
     701
     702/*
     703 * Flush a write buffer and wait for acknowledgement
     704 */
     705static int rtems_tftp_flush ( struct tftpStream *tp )
     706{
     707    int wlen, rlen;
     708    int retryCount = 0;
     709
     710    wlen = tp->nused + 2 * sizeof (rtems_unsigned16);
     711    for (;;) {
     712        tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
     713        tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
     714        if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
     715                                        (struct sockaddr *)&tp->farAddress,
     716                                        sizeof tp->farAddress) < 0)
     717            return EIO;
     718        rlen = getPacket (tp);
     719        if (rlen >= (int)sizeof tp->pkbuf.tftpACK) {
     720            int opcode = ntohs (tp->pkbuf.tftpACK.opcode);
     721            if ((opcode == TFTP_OPCODE_ACK)
     722             && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) {
     723                tp->nused = 0;
     724                tp->blocknum++;
     725                return 0;
     726            }
     727            if (opcode == TFTP_OPCODE_ERROR)
     728                return tftpErrno (tp);
     729        }
     730
     731        /*
     732         * Keep trying?
     733         */
     734        if (++retryCount == IO_RETRY_LIMIT)
     735            return EIO;
     736    }
     737}
     738
     739/*
     740 * Close a TFTP stream
     741 */
     742static int rtems_tftp_close(
     743    rtems_libio_t *iop
     744)
     745{
     746    struct tftpStream *tp = iop->data1;;
     747
     748    if (tp->writing)
     749        rtems_tftp_flush (tp);
     750    if (!tp->eof && !tp->firstReply) {
     751        /*
     752         * Tell the other end to stop
     753         */
     754        rtems_interval ticksPerSecond;
     755        sendStifle (tp, &tp->farAddress);
     756        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     757        rtems_task_wake_after (1 + ticksPerSecond / 10);
     758    }
     759    close (tp->socket);
     760    releaseStream (iop->data0);
     761    return RTEMS_SUCCESSFUL;
     762}
     763
     764static int rtems_tftp_write(
     765    rtems_libio_t   *iop,
     766    const void      *buffer,
     767    unsigned32      count
     768)
     769{
     770    const char        *bp;
     771    struct tftpStream *tp = iop->data1;
     772    int               nleft, nfree, ncopy;
     773
     774    /*
     775     * Bail out if an error has occurred
     776     */
     777    if (!tp->writing)
    594778        return EIO;
    595       }
    596     }
    597 
    598     /*
    599      * Keep trying
    600      */
    601     if (++retryCount >= OPEN_RETRY_LIMIT) {
    602       close (tp->socket);
    603       releaseStream (s);
    604       return EIO;
    605     }
    606   }
    607 
    608   return 0;
    609 }
    610 
    611 /*
    612  * Read from a TFTP stream
    613  */
    614 
    615 int rtems_tftp_read(
    616   rtems_libio_t *iop,
    617   void          *buffer,
    618   unsigned32     count
     779
     780
     781    /*
     782     * Write till user request is satisfied
     783     * Notice that the buffer is flushed as soon as it is filled rather
     784     * than waiting for the next write or a close.  This ensures that
     785     * the flush in close writes a less than full buffer so the far
     786     * end can detect the end-of-file condition.
     787     */
     788    bp = buffer;
     789    nleft = count;
     790    while (nleft) {
     791        nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused;
     792        if (nleft < nfree)
     793            ncopy = nleft;
     794        else
     795            ncopy = nfree;
     796        memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy);
     797        tp->nused += ncopy;
     798        nleft -= ncopy;
     799        bp += ncopy;
     800        if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) {
     801            int e = rtems_tftp_flush (tp);
     802            if (e) {
     803                tp->writing = 0;
     804                set_errno_and_return_minus_one (e);
     805            }
     806        }
     807    }
     808    return count;
     809}
     810
     811/*
     812 * Dummy version to let fopen(xxxx,"w") work properly.
     813 */
     814static int rtems_tftp_ftruncate(
     815    rtems_libio_t   *iop,
     816    off_t           count
    619817)
    620818{
    621   char              *bp;
    622   struct tftpStream *tp;
    623   int                retryCount;
    624   int                nwant;
    625 
    626   tp = iop->data1;
    627 
    628   /*
    629    * Read till user request is satisfied or EOF is reached
    630    */
    631 
    632   bp = buffer;
    633   nwant = count;
    634   while (nwant) {
    635     if (tp->nleft) {
    636       int count;
    637       if (nwant < tp->nleft)
    638         count = nwant;
    639       else
    640         count = tp->nleft;
    641       memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    642       tp->nused += count;
    643       tp->nleft -= count;
    644       bp += count;
    645       nwant -= count;
    646       if (nwant == 0)
    647         break;
    648     }
    649     if (tp->eof)
    650       break;
    651 
    652     /*
    653      * Wait for the next packet
    654      */
    655     retryCount = 0;
    656     for (;;) {
    657       int len = getPacket (tp);
    658       if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    659         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    660         rtems_unsigned16 nextBlock = tp->blocknum + 1;
    661         if ((opcode == TFTP_OPCODE_DATA)
    662          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    663           tp->nused = 0;
    664           tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    665           tp->eof = (tp->nleft < TFTP_BUFSIZE);
    666           tp->blocknum++;
    667           if (sendAck (tp) != 0)
    668             set_errno_and_return_minus_one( EIO );
    669           break;
    670         }
    671         if (opcode == TFTP_OPCODE_ERROR) {
    672           tftpSetErrno (tp);
    673           return RTEMS_INTERNAL_ERROR;
    674         }
    675       }
    676 
    677       /*
    678        * Keep trying?
    679        */
    680       if (++retryCount == IO_RETRY_LIMIT)
    681         set_errno_and_return_minus_one( EIO );
    682       if (sendAck (tp) != 0)
    683         set_errno_and_return_minus_one( EIO );
    684     }
    685   }
    686 
    687  /*
    688   * XXX - Eric is this right?
    689   *
    690   */
    691   return count - nwant;
    692 }
    693 
    694 /*
    695  * Close a TFTP stream
    696  */
    697 int rtems_tftp_close(
    698   rtems_libio_t *iop
     819    return 0;
     820}
     821
     822rtems_filesystem_node_types_t rtems_tftp_node_type(
     823     rtems_filesystem_location_info_t        *pathloc                 /* IN */
    699824)
    700825{
    701   struct tftpStream *tp = iop->data1;;
    702 
    703   if (!tp->eof && !tp->firstReply) {
    704     /*
    705      * Tell the other end to stop
    706      */
    707     rtems_interval ticksPerSecond;
    708     sendStifle (tp, &tp->farAddress);
    709     rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    710     rtems_task_wake_after (1 + ticksPerSecond / 10);
    711   }
    712   close (tp->socket);
    713   releaseStream (iop->data0);
    714   return RTEMS_SUCCESSFUL;
    715 }
    716 
    717 int rtems_tftp_write(
    718   rtems_libio_t *iop,
    719   const void    *buffer,
    720   unsigned32     count
    721 )
    722 {
    723   return RTEMS_NOT_CONFIGURED;
    724 }
    725 
    726 rtems_device_driver rtems_tftp_control(
    727   rtems_device_major_number major,
    728   rtems_device_minor_number minor,
    729   void *pargp
    730 )
    731 {
    732   return RTEMS_NOT_CONFIGURED;
    733 }
    734 
    735 rtems_filesystem_node_types_t rtems_tftp_node_type(
    736    rtems_filesystem_location_info_t    *pathloc         /* IN */
    737 )
    738 {
    739   return RTEMS_FILESYSTEM_MEMORY_FILE;
     826    return RTEMS_FILESYSTEM_MEMORY_FILE;
    740827}
    741828
    742829
    743830rtems_filesystem_operations_table  rtems_tftp_ops = {
    744   rtems_tftp_eval_path,            /* eval_path */
    745   rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
    746   NULL,                            /* link */
    747   NULL,                            /* unlink */
    748   rtems_tftp_node_type,            /* node_type */
    749   NULL,                            /* mknod */
    750   NULL,                            /* chown */
    751   NULL,                            /* freenodinfo */
    752   NULL,                            /* mount */
    753   rtems_tftp_mount_me,             /* initialize */
    754   NULL,                            /* unmount */
    755   NULL,                            /* fsunmount */
    756   NULL,                            /* utime, */
    757   NULL,                            /* evaluate_link */
    758   NULL,                            /* symlink */
    759   NULL,                            /* readlin */
     831    rtems_tftp_eval_path,            /* eval_path */
     832    rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     833    NULL,                            /* link */
     834    NULL,                            /* unlink */
     835    rtems_tftp_node_type,            /* node_type */
     836    NULL,                            /* mknod */
     837    NULL,                            /* chown */
     838    NULL,                            /* freenodinfo */
     839    NULL,                            /* mount */
     840    rtems_tftp_mount_me,             /* initialize */
     841    NULL,                            /* unmount */
     842    NULL,                            /* fsunmount */
     843    NULL,                            /* utime, */
     844    NULL,                            /* evaluate_link */
     845    NULL,                            /* symlink */
     846    NULL,                            /* readlin */
    760847};
    761 
     848 
    762849rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
    763   rtems_tftp_open,   /* open */     
    764   rtems_tftp_close,  /* close */   
    765   rtems_tftp_read,   /* read */     
    766   rtems_tftp_write,  /* write */   
    767   NULL,              /* ioctl */   
    768   NULL,              /* lseek */   
    769   NULL,              /* fstat */   
    770   NULL,              /* fchmod */   
    771   NULL,              /* ftruncate */
    772   NULL,              /* fpathconf */
    773   NULL,              /* fsync */   
    774   NULL,              /* fdatasync */
    775   NULL,              /* fcntl */
    776   NULL               /* rmnod */
     850    rtems_tftp_open,   /* open */     
     851    rtems_tftp_close,  /* close */   
     852    rtems_tftp_read,   /* read */     
     853    rtems_tftp_write,  /* write */   
     854    NULL,              /* ioctl */   
     855    NULL,              /* lseek */   
     856    NULL,              /* fstat */   
     857    NULL,              /* fchmod */   
     858    rtems_tftp_ftruncate, /* ftruncate */
     859    NULL,              /* fpathconf */
     860    NULL,              /* fsync */   
     861    NULL,              /* fdatasync */
     862    NULL,              /* fcntl */
     863    NULL               /* rmnod */
    777864};
Note: See TracChangeset for help on using the changeset viewer.