Changeset c1a37d3e in rtems


Ignore:
Timestamp:
Feb 4, 1999, 2:54:31 PM (20 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, master
Children:
8cce445
Parents:
7c7fd4d
Message:

Debugged and now works except for handling of minor number.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • c/src/exec/libnetworking/lib/tftpDriver.c

    r7c7fd4d rc1a37d3e  
    1919#include <string.h>
    2020#include <unistd.h>
     21#include <fcntl.h>
    2122#include <rtems.h>
    2223#include <rtems/libio.h>
     
    140141 * Number of streams open at the same time
    141142 */
     143
    142144static rtems_id tftp_mutex;
    143145static int nStreams;
    144146static struct tftpStream ** volatile tftpStreams;
    145147
    146 typedef struct {
    147    rtems_id                             tftp_mutex;
    148    int                                  nStreams;
    149    struct tftpStream ** volatile        tftpStreams;
    150   rtems_filesystem_mount_table_entry_t *mt_entry; 
    151 }  tftp_fs_info;
     148typedef const char *tftp_node;
     149extern rtems_filesystem_operations_table  rtems_tftp_ops;
     150extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;
     151
     152/*
     153 *  Direct copy from the IMFS.  Look at this.
     154 */
     155
     156rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
     157   5,   /* link_max */
     158   6,   /* max_canon */
     159   7,   /* max_input */
     160   255, /* name_max */
     161   255, /* path_max */
     162   2,   /* pipe_buf */
     163   1,   /* posix_async_io */
     164   2,   /* posix_chown_restrictions */
     165   3,   /* posix_no_trunc */
     166   4,   /* posix_prio_io */
     167   5,   /* posix_sync_io */
     168   6    /* posix_vdisable */
     169};
    152170
    153171int rtems_tftp_mount_me(
     
    155173)
    156174{
    157   tftp_fs_info      *fs_info;
    158175  rtems_status_code  sc;
    159176
    160   /*
    161    * Allocate stuff for this file system.
    162    */
    163 
    164   fs_info = calloc( 1, sizeof( tftp_fs_info ));
    165   if ( !fs_info )
    166     set_errno_and_return_minus_one( ENOMEM );
    167 
    168   temp_mt_entry->fs_info                = fs_info;
    169   temp_mt_entry->mt_fs_root.node_access = fs_info;
    170 
     177  temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
     178  temp_mt_entry->mt_fs_root.ops      = &rtems_tftp_ops;
     179
     180  /*
     181   *   We have no tftp filesystem specific data to maintain.  This
     182   *   filesystem may only be mounted ONCE.
     183   *
     184   *   And we maintain no real filesystem nodes, so there is no real root.
     185   */
     186
     187  temp_mt_entry->fs_info                = NULL;
     188  temp_mt_entry->mt_fs_root.node_access = NULL;
     189
     190  /*
     191   *  These need to be looked at for full POSIX semantics.
     192   */
     193
     194  temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
     195
     196
     197  /*
     198   *  Now allocate a semaphore for mutual exclusion.
     199   *
     200   *  NOTE:  This could be in an fsinfo for this filesystem type.
     201   */
    171202 
    172203  sc = rtems_semaphore_create (
     
    179210    RTEMS_LOCAL,
    180211    0,
    181     &fs_info->tftp_mutex
     212    &tftp_mutex
    182213  );
    183214
    184215  if (sc != RTEMS_SUCCESSFUL)
    185     set_errno_and_return_minus_one( ENOMEM ); /* ??? */
     216    set_errno_and_return_minus_one( ENOMEM );
    186217
    187218  return 0;
     
    191222 * Initialize the TFTP driver
    192223 */
    193 /* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
    194 /* XXX this won't be a driver when we are finished */
    195 rtems_device_driver rtems_tftp_initialize(
    196   rtems_device_major_number major,
    197   rtems_device_minor_number minor,
    198   void *pargp
    199 )
    200 {
    201 
    202 /* XXX change to a mount */
    203         rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
    204         return RTEMS_SUCCESSFUL;
     224
     225int rtems_bsdnet_initialize_tftp_filesystem ()
     226{
     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     "RO",
     238     NULL,
     239     TFTP_PATHNAME_PREFIX
     240  );
     241
     242  if ( status )
     243    perror( "TFTP mount failed" );
     244
     245  return status;
    205246}
    206247
     
    339380)
    340381
    341     set_errno_and_return_minus_one( EIO );   
    342 }
     382  set_errno_and_return_minus_one( EIO );   
     383}
     384
    343385/*
    344386 * XXX - Fix return values.
    345387 */
    346388
    347 int TFTP_eval_path( 
     389int rtems_tftp_eval_path( 
    348390  const char                        *pathname,     /* IN     */
    349391  int                                flags,        /* IN     */
     
    351393)
    352394{
    353         rtems_unsigned32 farAddress;
    354         int len;
    355         const char *remoteFilename;
    356 
    357   tftp_fs_info      *fs_info;
    358   const char *cp1, *cp2;
    359 
    360   fs_info = pathloc->node_access;
    361 
    362         /*
    363          * Pick apart the name into a host:pathname pair
    364          */
    365         /*
    366          * XXX - I think this is handled by the caller of
    367          *       the evaluate routine. ? Am I starting at the right
    368          *       place?
    369          */
    370 
    371         cp2 = pathname+1;
    372 
    373         if (*cp2 == '/') {
    374                 farAddress = rtems_bsdnet_bootp_server_address.s_addr;
    375         }
    376         else {
    377                 char *hostname;
    378 
    379                 cp1 = cp2;
    380                 while (*cp2 != '/') {
    381                         if (*cp2 == '\0')
    382                                 return RTEMS_INVALID_NAME;
    383                         cp2++;
    384                 }
    385                 len = cp2 - cp1;
    386                 hostname = malloc (len + 1);
    387                 if (hostname == NULL)
    388                         return RTEMS_NO_MEMORY;
    389                 strncpy (hostname, cp1, len);
    390                 hostname[len] = '\0';
    391                 farAddress = inet_addr (hostname);
    392                 free (hostname);
    393         }
    394         if ((farAddress == 0) || (farAddress == ~0))
    395                 return RTEMS_INVALID_NAME;
    396         if (*++cp2 == '\0')
    397                 return RTEMS_INVALID_NAME;
    398         remoteFilename = cp2;
    399         if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    400                 return RTEMS_INVALID_NAME;
     395
     396  /*
     397   * Read-only for now
     398   */
     399   
     400  if ( (flags & O_WRONLY) == O_WRONLY )
     401    set_errno_and_return_minus_one( ENOENT );
     402
     403  /*
     404   * The File system is mounted at TFTP_PATHNAME_PREFIX
     405   * the caller of this routine has striped off this part of the
     406   * name. Save the remainder of the name for use by the open routine.
     407   */
     408
     409  pathloc->node_access = (void * ) pathname;
     410  pathloc->handlers    = &rtems_tftp_handlers;
    401411
    402412  return 0;
    403413}
    404414
    405 /*
    406  * Open a TFTP stream
    407  */
    408 rtems_device_driver rtems_tftp_open(
    409   rtems_device_major_number major,
    410   rtems_device_minor_number minor,
    411   void *pargp
     415
     416int rtems_tftp_open(
     417  rtems_libio_t *iop,
     418  const char    *new_name,
     419  unsigned32     flag,
     420  unsigned32     mode
    412421)
    413422{
    414         rtems_libio_open_close_args_t *ap = pargp;
    415         struct tftpStream *tp;
    416         int retryCount;
    417         rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
    418         int s;
    419         int len;
    420         char *cp1, *cp2;
    421         char *remoteFilename = NULL; /* XXX - node parameter */
    422         rtems_interval now;
    423         rtems_status_code sc;
    424 
    425         /*
    426          * Read-only for now
    427          */
    428         /* XXX - Move to the open routine */
    429         if (ap->flags & LIBIO_FLAGS_WRITE)
    430                 return RTEMS_NOT_IMPLEMENTED;
    431 
    432 
    433         /*
    434          * Find a free stream
    435          */
    436         sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    437         if (sc != RTEMS_SUCCESSFUL)
    438                 return sc;
    439         for (s = 0 ; s < nStreams ; s++) {
    440                 if (tftpStreams[s] == NULL)
    441                         break;
    442         }
    443         if (s == nStreams) {
    444                 /*
    445                  * Reallocate stream pointers
    446                  * Guard against the case where realloc() returns NULL.
    447                  */
    448                 struct tftpStream **np;
    449 
    450                 np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    451                 if (np == NULL) {
    452                         rtems_semaphore_release (tftp_mutex);
    453                         return RTEMS_NO_MEMORY;
    454                 }
    455                 tftpStreams = np;
    456         }
    457         tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    458         rtems_semaphore_release (tftp_mutex);
    459         if (tp == NULL)
    460                 return RTEMS_NO_MEMORY;
    461         ap->iop->data0 = s;
    462         ap->iop->data1 = tp;
    463 
    464         /*
    465          * Create the socket
    466          */
    467         if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    468                 releaseStream (s);
    469                 return RTEMS_TOO_MANY;
    470         }
    471 
    472         /*
    473          * Bind the socket to a local address
    474          */
    475         retryCount = 0;
    476         rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    477         for (;;) {
    478                 int try = (now + retryCount) % 10;
    479 
    480                 tp->myAddress.sin_family = AF_INET;
    481                 tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
    482                 tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    483                 if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    484                         break;
    485                 if (++retryCount == 10) {
    486                         close (tp->socket);
    487                         releaseStream (minor);
    488                         return RTEMS_RESOURCE_IN_USE;
    489                 }
    490         }
    491 
    492         /*
    493          * Set the UDP destination to the TFTP server
    494          * port on the remote machine.
    495          */
    496         tp->farAddress.sin_family = AF_INET;
    497         tp->farAddress.sin_addr.s_addr = farAddress;
    498         tp->farAddress.sin_port = htons (69);
    499 
    500         /*
    501          * Start the transfer
    502          */
    503         tp->firstReply = 1;
    504         for (;;) {
    505                 /*
    506                  * Create the request
    507                  */
    508                 tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    509                 cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
    510                 cp2 = remoteFilename;
    511                 while ((*cp1++ = *cp2++) != '\0')
    512                         continue;
    513                 cp2 = "octet";
    514                 while ((*cp1++ = *cp2++) != '\0')
    515                         continue;
    516                 len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    517 
    518                 /*
    519                  * Send the request
    520                  */
    521                 if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    522                                         (struct sockaddr *)&tp->farAddress,
    523                                         sizeof tp->farAddress) < 0) {
    524                         close (tp->socket);
    525                         releaseStream (minor);
    526                         return RTEMS_UNSATISFIED;
    527                 }
    528 
    529                 /*
    530                  * Get reply
    531                  */
    532                 len = getPacket (tp);
    533                 if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    534                         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    535                         if ((opcode == TFTP_OPCODE_DATA)
    536                          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    537                                 tp->nused = 0;
    538                                 tp->blocknum = 1;
    539                                 tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    540                                 tp->eof = (tp->nleft < TFTP_BUFSIZE);
    541                                 if (sendAck (tp) != 0) {
    542                                         close (tp->socket);
    543                                         releaseStream (minor);
    544                                         return RTEMS_UNSATISFIED;
    545                                 }
    546                                 break;
    547                         }
    548                         if (opcode == TFTP_OPCODE_ERROR) {
    549                                 tftpSetErrno (tp);
    550                                 close (tp->socket);
    551                                 releaseStream (ap->iop->data0);
    552                                 return RTEMS_INTERNAL_ERROR;
    553                         }
    554                 }
    555 
    556                 /*
    557                  * Keep trying
    558                  */
    559                 if (++retryCount >= OPEN_RETRY_LIMIT) {
    560                         close (tp->socket);
    561                         releaseStream (minor);
    562                         return RTEMS_UNSATISFIED;
    563                 }
    564         }
    565         return RTEMS_SUCCESSFUL;
     423  struct tftpStream  *tp;
     424  int                 retryCount;
     425  rtems_unsigned32    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
     434  /*
     435   * This came from the evaluate path.
     436   */
     437
     438  cp2 = iop->file_info; 
     439  if (*cp2 == '/') {
     440    farAddress = rtems_bsdnet_bootp_server_address.s_addr;
     441  }
     442  else {
     443    char *hostname;
     444
     445    cp1 = cp2;
     446    while (*cp2 != '/') {
     447      if (*cp2 == '\0')
     448        set_errno_and_return_minus_one( ENOENT );
     449       cp2++;
     450    }
     451
     452    len = cp2 - cp1;
     453    hostname = malloc (len + 1);
     454    if (hostname == NULL)
     455      set_errno_and_return_minus_one( ENOMEM );
     456
     457    strncpy (hostname, cp1, len);
     458    hostname[len] = '\0';
     459    farAddress = inet_addr (hostname);
     460    free (hostname);
     461  }
     462
     463  if ((farAddress == 0) || (farAddress == ~0))
     464    set_errno_and_return_minus_one( ENOENT );
     465
     466  if (*++cp2 == '\0')
     467    set_errno_and_return_minus_one( ENOENT );
     468
     469  remoteFilename = cp2;
     470  if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     471    set_errno_and_return_minus_one( ENOENT );
     472
     473  /*
     474   * Find a free stream
     475   */
     476
     477  sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     478  if (sc != RTEMS_SUCCESSFUL)
     479    set_errno_and_return_minus_one( EBUSY );
     480
     481  for (s = 0 ; s < nStreams ; s++) {
     482    if (tftpStreams[s] == NULL)
     483    break;
     484  }
     485
     486  if (s == nStreams) {
     487    /*
     488     * Reallocate stream pointers
     489     * Guard against the case where realloc() returns NULL.
     490     */
     491    struct tftpStream **np;
     492
     493    np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     494    if (np == NULL) {
     495      rtems_semaphore_release (tftp_mutex);
     496      set_errno_and_return_minus_one( ENOMEM );
     497    }
     498    tftpStreams = np;
     499  }
     500
     501  tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     502  rtems_semaphore_release (tftp_mutex);
     503  if (tp == NULL)
     504    set_errno_and_return_minus_one( ENOMEM );
     505  iop->data0 = s;
     506  iop->data1 = tp;
     507
     508  /*
     509   * Create the socket
     510   */
     511
     512  if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
     513    releaseStream (s);
     514    set_errno_and_return_minus_one( ENOMEM );
     515  }
     516
     517  /*
     518   * Bind the socket to a local address
     519   */
     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    /*
     528     *  XXX Eric .. how do we get the minor information???
     529     * tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
     530     */
     531    tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
     532    tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     533    if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     534      break;
     535    if (++retryCount == 10) {
     536      close (tp->socket);
     537      /*
     538       *  XXX Eric .. how do we get the minor information to release this???
     539        releaseStream (minor);
     540       */
     541      set_errno_and_return_minus_one( EBUSY );
     542    }
     543  }
     544
     545  /*
     546   * Set the UDP destination to the TFTP server
     547   * port on the remote machine.
     548   */
     549  tp->farAddress.sin_family = AF_INET;
     550  tp->farAddress.sin_addr.s_addr = farAddress;
     551  tp->farAddress.sin_port = htons (69);
     552
     553  /*
     554   * Start the transfer
     555   */
     556  tp->firstReply = 1;
     557  for (;;) {
     558    /*
     559     * Create the request
     560     */
     561    tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     562      /*
     563       *  XXX Eric .. is this cast taking the const off right?
     564       */
     565
     566    cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     567    cp2 = (char *) remoteFilename;
     568    while ((*cp1++ = *cp2++) != '\0')
     569      continue;
     570    cp2 = "octet";
     571    while ((*cp1++ = *cp2++) != '\0')
     572      continue;
     573    len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     574
     575    /*
     576     * Send the request
     577     */
     578    if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     579          (struct sockaddr *)&tp->farAddress,
     580          sizeof tp->farAddress) < 0) {
     581      close (tp->socket);
     582      /*
     583       *  XXX Eric .. how do we get the minor information to release this???
     584        releaseStream (minor);
     585       */
     586      set_errno_and_return_minus_one( EIO );
     587    }
     588
     589    /*
     590     * Get reply
     591     */
     592    len = getPacket (tp);
     593    if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     594      int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     595      if ((opcode == TFTP_OPCODE_DATA)
     596       && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     597        tp->nused = 0;
     598        tp->blocknum = 1;
     599        tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     600        tp->eof = (tp->nleft < TFTP_BUFSIZE);
     601        if (sendAck (tp) != 0) {
     602          close (tp->socket);
     603      /*
     604       *  XXX Eric .. how do we get the minor information to release this???
     605          releaseStream (minor);
     606       */
     607
     608          set_errno_and_return_minus_one( EIO );
     609        }
     610        break;
     611      }
     612      if (opcode == TFTP_OPCODE_ERROR) {
     613        tftpSetErrno (tp);
     614        close (tp->socket);
     615      /*
     616       *  XXX Eric .. how do we get the minor information to release this???
     617       *  releaseStream (minor);
     618       */
     619        set_errno_and_return_minus_one( EIO );
     620      }
     621    }
     622
     623    /*
     624     * Keep trying
     625     */
     626    if (++retryCount >= OPEN_RETRY_LIMIT) {
     627      close (tp->socket);
     628      /*
     629       *  XXX Eric .. how do we get the minor information to release this???
     630        releaseStream (minor);
     631       */
     632      set_errno_and_return_minus_one( EIO );
     633    }
     634  }
     635
     636  return 0;
    566637}
    567638
     
    569640 * Read from a TFTP stream
    570641 */
    571 rtems_device_driver rtems_tftp_read(
    572   rtems_device_major_number major,
    573   rtems_device_minor_number minor,
    574   void *pargp
     642
     643int rtems_tftp_read(
     644  rtems_libio_t *iop,
     645  void          *buffer,
     646  unsigned32     count
    575647)
    576648{
    577         rtems_libio_rw_args_t *ap = pargp;
    578         char *bp;
    579         struct tftpStream *tp;
    580         int retryCount;
    581         int nwant;
    582 
    583         tp = ap->iop->data1;
    584 
    585         /*
    586          * Read till user request is satisfied or EOF is reached
    587          */
    588         bp = ap->buffer;
    589         nwant = ap->count;
    590         while (nwant) {
    591                 if (tp->nleft) {
    592                         int count;
    593                         if (nwant < tp->nleft)
    594                                 count = nwant;
    595                         else
    596                                 count = tp->nleft;
    597                         memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    598                         tp->nused += count;
    599                         tp->nleft -= count;
    600                         bp += count;
    601                         nwant -= count;
    602                         if (nwant == 0)
    603                                 break;
    604                 }
    605                 if (tp->eof)
    606                         break;
    607 
    608                 /*
    609                  * Wait for the next packet
    610                  */
    611                 retryCount = 0;
    612                 for (;;) {
    613                         int len = getPacket (tp);
    614                         if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    615                                 int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    616                                 rtems_unsigned16 nextBlock = tp->blocknum + 1;
    617                                 if ((opcode == TFTP_OPCODE_DATA)
    618                                  && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    619                                         tp->nused = 0;
    620                                         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    621                                         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    622                                         tp->blocknum++;
    623                                         if (sendAck (tp) != 0)
    624                                                 return RTEMS_IO_ERROR;
    625                                         break;
    626                                 }
    627                                 if (opcode == TFTP_OPCODE_ERROR) {
    628                                         tftpSetErrno (tp);
    629                                         return RTEMS_INTERNAL_ERROR;
    630                                 }
    631                         }
    632 
    633                         /*
    634                          * Keep trying?
    635                          */
    636                         if (++retryCount == IO_RETRY_LIMIT)
    637                                 return RTEMS_IO_ERROR;
    638                         if (sendAck (tp) != 0)
    639                                 return RTEMS_IO_ERROR;
    640                 }
    641         }
    642         ap->bytes_moved = ap->count - nwant;
    643         return RTEMS_SUCCESSFUL;
     649  char              *bp;
     650  struct tftpStream *tp;
     651  int                retryCount;
     652  int                nwant;
     653
     654  tp = iop->data1;
     655
     656  /*
     657   * Read till user request is satisfied or EOF is reached
     658   */
     659
     660  bp = buffer;
     661  nwant = count;
     662  while (nwant) {
     663    if (tp->nleft) {
     664      int count;
     665      if (nwant < tp->nleft)
     666        count = nwant;
     667      else
     668        count = tp->nleft;
     669      memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
     670      tp->nused += count;
     671      tp->nleft -= count;
     672      bp += count;
     673      nwant -= count;
     674      if (nwant == 0)
     675        break;
     676    }
     677    if (tp->eof)
     678      break;
     679
     680    /*
     681     * Wait for the next packet
     682     */
     683    retryCount = 0;
     684    for (;;) {
     685      int len = getPacket (tp);
     686      if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     687        int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     688        rtems_unsigned16 nextBlock = tp->blocknum + 1;
     689        if ((opcode == TFTP_OPCODE_DATA)
     690         && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     691          tp->nused = 0;
     692          tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     693          tp->eof = (tp->nleft < TFTP_BUFSIZE);
     694          tp->blocknum++;
     695          if (sendAck (tp) != 0)
     696            set_errno_and_return_minus_one( EIO );
     697          break;
     698        }
     699        if (opcode == TFTP_OPCODE_ERROR) {
     700          tftpSetErrno (tp);
     701          return RTEMS_INTERNAL_ERROR;
     702        }
     703      }
     704
     705      /*
     706       * Keep trying?
     707       */
     708      if (++retryCount == IO_RETRY_LIMIT)
     709        set_errno_and_return_minus_one( EIO );
     710      if (sendAck (tp) != 0)
     711        set_errno_and_return_minus_one( EIO );
     712    }
     713  }
     714
     715 /*
     716  * XXX - Eric is this right?
     717  *
     718  */
     719  return count - nwant;
    644720}
    645721
     
    647723 * Close a TFTP stream
    648724 */
    649 rtems_device_driver rtems_tftp_close(
    650   rtems_device_major_number major,
    651   rtems_device_minor_number minor,
    652   void *pargp
     725int rtems_tftp_close(
     726  rtems_libio_t *iop
    653727)
    654728{
    655         rtems_libio_open_close_args_t *ap = pargp;
    656         struct tftpStream *tp = ap->iop->data1;;
    657 
    658         if (!tp->eof && !tp->firstReply) {
    659                 /*
    660                  * Tell the other end to stop
    661                  */
    662                 rtems_interval ticksPerSecond;
    663                 sendStifle (tp, &tp->farAddress);
    664                 rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    665                 rtems_task_wake_after (1 + ticksPerSecond / 10);
    666         }
    667         close (tp->socket);
    668         releaseStream (ap->iop->data0);
    669         return RTEMS_SUCCESSFUL;
    670 }
    671 
    672 rtems_device_driver rtems_tftp_write(
    673   rtems_device_major_number major,
    674   rtems_device_minor_number minor,
    675   void *pargp
     729  struct tftpStream *tp = iop->data1;;
     730
     731  if (!tp->eof && !tp->firstReply) {
     732    /*
     733     * Tell the other end to stop
     734     */
     735    rtems_interval ticksPerSecond;
     736    sendStifle (tp, &tp->farAddress);
     737    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     738    rtems_task_wake_after (1 + ticksPerSecond / 10);
     739  }
     740  close (tp->socket);
     741  releaseStream (iop->data0);
     742  return RTEMS_SUCCESSFUL;
     743}
     744
     745int rtems_tftp_write(
     746  rtems_libio_t *iop,
     747  const void    *buffer,
     748  unsigned32     count
    676749)
    677750{
    678         return RTEMS_NOT_CONFIGURED;
     751  return RTEMS_NOT_CONFIGURED;
    679752}
    680753
     
    685758)
    686759{
    687         return RTEMS_NOT_CONFIGURED;
    688 }
     760  return RTEMS_NOT_CONFIGURED;
     761}
     762
     763rtems_filesystem_node_types_t rtems_tftp_node_type(
     764   rtems_filesystem_location_info_t    *pathloc         /* IN */
     765)
     766{
     767  return RTEMS_FILESYSTEM_MEMORY_FILE;
     768}
     769
     770
     771rtems_filesystem_operations_table  rtems_tftp_ops = {
     772  rtems_tftp_eval_path,            /* eval_path */
     773  rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     774  NULL,                            /* link */
     775  NULL,                            /* unlink */
     776  rtems_tftp_node_type,            /* node_type */
     777  NULL,                            /* mknod */
     778  NULL,                            /* rmnod */
     779  NULL,                            /* chown */
     780  NULL,                            /* freenodinfo */
     781  NULL,                            /* mount */
     782  rtems_tftp_mount_me,             /* initialize */
     783  NULL,                            /* unmount */
     784  NULL,                            /* fsunmount */
     785  NULL,                            /* utime, */
     786  NULL,                            /* evaluate_link */
     787  NULL,                            /* symlink */
     788  NULL,                            /* readlin */
     789};
     790
     791rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
     792  rtems_tftp_open,
     793  rtems_tftp_close,
     794  rtems_tftp_read,
     795  rtems_tftp_write,
     796  NULL,
     797  NULL,
     798  NULL,
     799  NULL,
     800  NULL,
     801  NULL,
     802  NULL,
     803  NULL,
     804};
  • c/src/lib/libnetworking/lib/tftpDriver.c

    r7c7fd4d rc1a37d3e  
    1919#include <string.h>
    2020#include <unistd.h>
     21#include <fcntl.h>
    2122#include <rtems.h>
    2223#include <rtems/libio.h>
     
    140141 * Number of streams open at the same time
    141142 */
     143
    142144static rtems_id tftp_mutex;
    143145static int nStreams;
    144146static struct tftpStream ** volatile tftpStreams;
    145147
    146 typedef struct {
    147    rtems_id                             tftp_mutex;
    148    int                                  nStreams;
    149    struct tftpStream ** volatile        tftpStreams;
    150   rtems_filesystem_mount_table_entry_t *mt_entry; 
    151 }  tftp_fs_info;
     148typedef const char *tftp_node;
     149extern rtems_filesystem_operations_table  rtems_tftp_ops;
     150extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;
     151
     152/*
     153 *  Direct copy from the IMFS.  Look at this.
     154 */
     155
     156rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
     157   5,   /* link_max */
     158   6,   /* max_canon */
     159   7,   /* max_input */
     160   255, /* name_max */
     161   255, /* path_max */
     162   2,   /* pipe_buf */
     163   1,   /* posix_async_io */
     164   2,   /* posix_chown_restrictions */
     165   3,   /* posix_no_trunc */
     166   4,   /* posix_prio_io */
     167   5,   /* posix_sync_io */
     168   6    /* posix_vdisable */
     169};
    152170
    153171int rtems_tftp_mount_me(
     
    155173)
    156174{
    157   tftp_fs_info      *fs_info;
    158175  rtems_status_code  sc;
    159176
    160   /*
    161    * Allocate stuff for this file system.
    162    */
    163 
    164   fs_info = calloc( 1, sizeof( tftp_fs_info ));
    165   if ( !fs_info )
    166     set_errno_and_return_minus_one( ENOMEM );
    167 
    168   temp_mt_entry->fs_info                = fs_info;
    169   temp_mt_entry->mt_fs_root.node_access = fs_info;
    170 
     177  temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
     178  temp_mt_entry->mt_fs_root.ops      = &rtems_tftp_ops;
     179
     180  /*
     181   *   We have no tftp filesystem specific data to maintain.  This
     182   *   filesystem may only be mounted ONCE.
     183   *
     184   *   And we maintain no real filesystem nodes, so there is no real root.
     185   */
     186
     187  temp_mt_entry->fs_info                = NULL;
     188  temp_mt_entry->mt_fs_root.node_access = NULL;
     189
     190  /*
     191   *  These need to be looked at for full POSIX semantics.
     192   */
     193
     194  temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
     195
     196
     197  /*
     198   *  Now allocate a semaphore for mutual exclusion.
     199   *
     200   *  NOTE:  This could be in an fsinfo for this filesystem type.
     201   */
    171202 
    172203  sc = rtems_semaphore_create (
     
    179210    RTEMS_LOCAL,
    180211    0,
    181     &fs_info->tftp_mutex
     212    &tftp_mutex
    182213  );
    183214
    184215  if (sc != RTEMS_SUCCESSFUL)
    185     set_errno_and_return_minus_one( ENOMEM ); /* ??? */
     216    set_errno_and_return_minus_one( ENOMEM );
    186217
    187218  return 0;
     
    191222 * Initialize the TFTP driver
    192223 */
    193 /* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
    194 /* XXX this won't be a driver when we are finished */
    195 rtems_device_driver rtems_tftp_initialize(
    196   rtems_device_major_number major,
    197   rtems_device_minor_number minor,
    198   void *pargp
    199 )
    200 {
    201 
    202 /* XXX change to a mount */
    203         rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
    204         return RTEMS_SUCCESSFUL;
     224
     225int rtems_bsdnet_initialize_tftp_filesystem ()
     226{
     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     "RO",
     238     NULL,
     239     TFTP_PATHNAME_PREFIX
     240  );
     241
     242  if ( status )
     243    perror( "TFTP mount failed" );
     244
     245  return status;
    205246}
    206247
     
    339380)
    340381
    341     set_errno_and_return_minus_one( EIO );   
    342 }
     382  set_errno_and_return_minus_one( EIO );   
     383}
     384
    343385/*
    344386 * XXX - Fix return values.
    345387 */
    346388
    347 int TFTP_eval_path( 
     389int rtems_tftp_eval_path( 
    348390  const char                        *pathname,     /* IN     */
    349391  int                                flags,        /* IN     */
     
    351393)
    352394{
    353         rtems_unsigned32 farAddress;
    354         int len;
    355         const char *remoteFilename;
    356 
    357   tftp_fs_info      *fs_info;
    358   const char *cp1, *cp2;
    359 
    360   fs_info = pathloc->node_access;
    361 
    362         /*
    363          * Pick apart the name into a host:pathname pair
    364          */
    365         /*
    366          * XXX - I think this is handled by the caller of
    367          *       the evaluate routine. ? Am I starting at the right
    368          *       place?
    369          */
    370 
    371         cp2 = pathname+1;
    372 
    373         if (*cp2 == '/') {
    374                 farAddress = rtems_bsdnet_bootp_server_address.s_addr;
    375         }
    376         else {
    377                 char *hostname;
    378 
    379                 cp1 = cp2;
    380                 while (*cp2 != '/') {
    381                         if (*cp2 == '\0')
    382                                 return RTEMS_INVALID_NAME;
    383                         cp2++;
    384                 }
    385                 len = cp2 - cp1;
    386                 hostname = malloc (len + 1);
    387                 if (hostname == NULL)
    388                         return RTEMS_NO_MEMORY;
    389                 strncpy (hostname, cp1, len);
    390                 hostname[len] = '\0';
    391                 farAddress = inet_addr (hostname);
    392                 free (hostname);
    393         }
    394         if ((farAddress == 0) || (farAddress == ~0))
    395                 return RTEMS_INVALID_NAME;
    396         if (*++cp2 == '\0')
    397                 return RTEMS_INVALID_NAME;
    398         remoteFilename = cp2;
    399         if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    400                 return RTEMS_INVALID_NAME;
     395
     396  /*
     397   * Read-only for now
     398   */
     399   
     400  if ( (flags & O_WRONLY) == O_WRONLY )
     401    set_errno_and_return_minus_one( ENOENT );
     402
     403  /*
     404   * The File system is mounted at TFTP_PATHNAME_PREFIX
     405   * the caller of this routine has striped off this part of the
     406   * name. Save the remainder of the name for use by the open routine.
     407   */
     408
     409  pathloc->node_access = (void * ) pathname;
     410  pathloc->handlers    = &rtems_tftp_handlers;
    401411
    402412  return 0;
    403413}
    404414
    405 /*
    406  * Open a TFTP stream
    407  */
    408 rtems_device_driver rtems_tftp_open(
    409   rtems_device_major_number major,
    410   rtems_device_minor_number minor,
    411   void *pargp
     415
     416int rtems_tftp_open(
     417  rtems_libio_t *iop,
     418  const char    *new_name,
     419  unsigned32     flag,
     420  unsigned32     mode
    412421)
    413422{
    414         rtems_libio_open_close_args_t *ap = pargp;
    415         struct tftpStream *tp;
    416         int retryCount;
    417         rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
    418         int s;
    419         int len;
    420         char *cp1, *cp2;
    421         char *remoteFilename = NULL; /* XXX - node parameter */
    422         rtems_interval now;
    423         rtems_status_code sc;
    424 
    425         /*
    426          * Read-only for now
    427          */
    428         /* XXX - Move to the open routine */
    429         if (ap->flags & LIBIO_FLAGS_WRITE)
    430                 return RTEMS_NOT_IMPLEMENTED;
    431 
    432 
    433         /*
    434          * Find a free stream
    435          */
    436         sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    437         if (sc != RTEMS_SUCCESSFUL)
    438                 return sc;
    439         for (s = 0 ; s < nStreams ; s++) {
    440                 if (tftpStreams[s] == NULL)
    441                         break;
    442         }
    443         if (s == nStreams) {
    444                 /*
    445                  * Reallocate stream pointers
    446                  * Guard against the case where realloc() returns NULL.
    447                  */
    448                 struct tftpStream **np;
    449 
    450                 np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    451                 if (np == NULL) {
    452                         rtems_semaphore_release (tftp_mutex);
    453                         return RTEMS_NO_MEMORY;
    454                 }
    455                 tftpStreams = np;
    456         }
    457         tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    458         rtems_semaphore_release (tftp_mutex);
    459         if (tp == NULL)
    460                 return RTEMS_NO_MEMORY;
    461         ap->iop->data0 = s;
    462         ap->iop->data1 = tp;
    463 
    464         /*
    465          * Create the socket
    466          */
    467         if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    468                 releaseStream (s);
    469                 return RTEMS_TOO_MANY;
    470         }
    471 
    472         /*
    473          * Bind the socket to a local address
    474          */
    475         retryCount = 0;
    476         rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    477         for (;;) {
    478                 int try = (now + retryCount) % 10;
    479 
    480                 tp->myAddress.sin_family = AF_INET;
    481                 tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
    482                 tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    483                 if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    484                         break;
    485                 if (++retryCount == 10) {
    486                         close (tp->socket);
    487                         releaseStream (minor);
    488                         return RTEMS_RESOURCE_IN_USE;
    489                 }
    490         }
    491 
    492         /*
    493          * Set the UDP destination to the TFTP server
    494          * port on the remote machine.
    495          */
    496         tp->farAddress.sin_family = AF_INET;
    497         tp->farAddress.sin_addr.s_addr = farAddress;
    498         tp->farAddress.sin_port = htons (69);
    499 
    500         /*
    501          * Start the transfer
    502          */
    503         tp->firstReply = 1;
    504         for (;;) {
    505                 /*
    506                  * Create the request
    507                  */
    508                 tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    509                 cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
    510                 cp2 = remoteFilename;
    511                 while ((*cp1++ = *cp2++) != '\0')
    512                         continue;
    513                 cp2 = "octet";
    514                 while ((*cp1++ = *cp2++) != '\0')
    515                         continue;
    516                 len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    517 
    518                 /*
    519                  * Send the request
    520                  */
    521                 if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    522                                         (struct sockaddr *)&tp->farAddress,
    523                                         sizeof tp->farAddress) < 0) {
    524                         close (tp->socket);
    525                         releaseStream (minor);
    526                         return RTEMS_UNSATISFIED;
    527                 }
    528 
    529                 /*
    530                  * Get reply
    531                  */
    532                 len = getPacket (tp);
    533                 if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    534                         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    535                         if ((opcode == TFTP_OPCODE_DATA)
    536                          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    537                                 tp->nused = 0;
    538                                 tp->blocknum = 1;
    539                                 tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    540                                 tp->eof = (tp->nleft < TFTP_BUFSIZE);
    541                                 if (sendAck (tp) != 0) {
    542                                         close (tp->socket);
    543                                         releaseStream (minor);
    544                                         return RTEMS_UNSATISFIED;
    545                                 }
    546                                 break;
    547                         }
    548                         if (opcode == TFTP_OPCODE_ERROR) {
    549                                 tftpSetErrno (tp);
    550                                 close (tp->socket);
    551                                 releaseStream (ap->iop->data0);
    552                                 return RTEMS_INTERNAL_ERROR;
    553                         }
    554                 }
    555 
    556                 /*
    557                  * Keep trying
    558                  */
    559                 if (++retryCount >= OPEN_RETRY_LIMIT) {
    560                         close (tp->socket);
    561                         releaseStream (minor);
    562                         return RTEMS_UNSATISFIED;
    563                 }
    564         }
    565         return RTEMS_SUCCESSFUL;
     423  struct tftpStream  *tp;
     424  int                 retryCount;
     425  rtems_unsigned32    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
     434  /*
     435   * This came from the evaluate path.
     436   */
     437
     438  cp2 = iop->file_info; 
     439  if (*cp2 == '/') {
     440    farAddress = rtems_bsdnet_bootp_server_address.s_addr;
     441  }
     442  else {
     443    char *hostname;
     444
     445    cp1 = cp2;
     446    while (*cp2 != '/') {
     447      if (*cp2 == '\0')
     448        set_errno_and_return_minus_one( ENOENT );
     449       cp2++;
     450    }
     451
     452    len = cp2 - cp1;
     453    hostname = malloc (len + 1);
     454    if (hostname == NULL)
     455      set_errno_and_return_minus_one( ENOMEM );
     456
     457    strncpy (hostname, cp1, len);
     458    hostname[len] = '\0';
     459    farAddress = inet_addr (hostname);
     460    free (hostname);
     461  }
     462
     463  if ((farAddress == 0) || (farAddress == ~0))
     464    set_errno_and_return_minus_one( ENOENT );
     465
     466  if (*++cp2 == '\0')
     467    set_errno_and_return_minus_one( ENOENT );
     468
     469  remoteFilename = cp2;
     470  if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     471    set_errno_and_return_minus_one( ENOENT );
     472
     473  /*
     474   * Find a free stream
     475   */
     476
     477  sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     478  if (sc != RTEMS_SUCCESSFUL)
     479    set_errno_and_return_minus_one( EBUSY );
     480
     481  for (s = 0 ; s < nStreams ; s++) {
     482    if (tftpStreams[s] == NULL)
     483    break;
     484  }
     485
     486  if (s == nStreams) {
     487    /*
     488     * Reallocate stream pointers
     489     * Guard against the case where realloc() returns NULL.
     490     */
     491    struct tftpStream **np;
     492
     493    np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     494    if (np == NULL) {
     495      rtems_semaphore_release (tftp_mutex);
     496      set_errno_and_return_minus_one( ENOMEM );
     497    }
     498    tftpStreams = np;
     499  }
     500
     501  tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     502  rtems_semaphore_release (tftp_mutex);
     503  if (tp == NULL)
     504    set_errno_and_return_minus_one( ENOMEM );
     505  iop->data0 = s;
     506  iop->data1 = tp;
     507
     508  /*
     509   * Create the socket
     510   */
     511
     512  if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
     513    releaseStream (s);
     514    set_errno_and_return_minus_one( ENOMEM );
     515  }
     516
     517  /*
     518   * Bind the socket to a local address
     519   */
     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    /*
     528     *  XXX Eric .. how do we get the minor information???
     529     * tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
     530     */
     531    tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
     532    tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     533    if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     534      break;
     535    if (++retryCount == 10) {
     536      close (tp->socket);
     537      /*
     538       *  XXX Eric .. how do we get the minor information to release this???
     539        releaseStream (minor);
     540       */
     541      set_errno_and_return_minus_one( EBUSY );
     542    }
     543  }
     544
     545  /*
     546   * Set the UDP destination to the TFTP server
     547   * port on the remote machine.
     548   */
     549  tp->farAddress.sin_family = AF_INET;
     550  tp->farAddress.sin_addr.s_addr = farAddress;
     551  tp->farAddress.sin_port = htons (69);
     552
     553  /*
     554   * Start the transfer
     555   */
     556  tp->firstReply = 1;
     557  for (;;) {
     558    /*
     559     * Create the request
     560     */
     561    tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     562      /*
     563       *  XXX Eric .. is this cast taking the const off right?
     564       */
     565
     566    cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     567    cp2 = (char *) remoteFilename;
     568    while ((*cp1++ = *cp2++) != '\0')
     569      continue;
     570    cp2 = "octet";
     571    while ((*cp1++ = *cp2++) != '\0')
     572      continue;
     573    len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     574
     575    /*
     576     * Send the request
     577     */
     578    if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     579          (struct sockaddr *)&tp->farAddress,
     580          sizeof tp->farAddress) < 0) {
     581      close (tp->socket);
     582      /*
     583       *  XXX Eric .. how do we get the minor information to release this???
     584        releaseStream (minor);
     585       */
     586      set_errno_and_return_minus_one( EIO );
     587    }
     588
     589    /*
     590     * Get reply
     591     */
     592    len = getPacket (tp);
     593    if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     594      int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     595      if ((opcode == TFTP_OPCODE_DATA)
     596       && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     597        tp->nused = 0;
     598        tp->blocknum = 1;
     599        tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     600        tp->eof = (tp->nleft < TFTP_BUFSIZE);
     601        if (sendAck (tp) != 0) {
     602          close (tp->socket);
     603      /*
     604       *  XXX Eric .. how do we get the minor information to release this???
     605          releaseStream (minor);
     606       */
     607
     608          set_errno_and_return_minus_one( EIO );
     609        }
     610        break;
     611      }
     612      if (opcode == TFTP_OPCODE_ERROR) {
     613        tftpSetErrno (tp);
     614        close (tp->socket);
     615      /*
     616       *  XXX Eric .. how do we get the minor information to release this???
     617       *  releaseStream (minor);
     618       */
     619        set_errno_and_return_minus_one( EIO );
     620      }
     621    }
     622
     623    /*
     624     * Keep trying
     625     */
     626    if (++retryCount >= OPEN_RETRY_LIMIT) {
     627      close (tp->socket);
     628      /*
     629       *  XXX Eric .. how do we get the minor information to release this???
     630        releaseStream (minor);
     631       */
     632      set_errno_and_return_minus_one( EIO );
     633    }
     634  }
     635
     636  return 0;
    566637}
    567638
     
    569640 * Read from a TFTP stream
    570641 */
    571 rtems_device_driver rtems_tftp_read(
    572   rtems_device_major_number major,
    573   rtems_device_minor_number minor,
    574   void *pargp
     642
     643int rtems_tftp_read(
     644  rtems_libio_t *iop,
     645  void          *buffer,
     646  unsigned32     count
    575647)
    576648{
    577         rtems_libio_rw_args_t *ap = pargp;
    578         char *bp;
    579         struct tftpStream *tp;
    580         int retryCount;
    581         int nwant;
    582 
    583         tp = ap->iop->data1;
    584 
    585         /*
    586          * Read till user request is satisfied or EOF is reached
    587          */
    588         bp = ap->buffer;
    589         nwant = ap->count;
    590         while (nwant) {
    591                 if (tp->nleft) {
    592                         int count;
    593                         if (nwant < tp->nleft)
    594                                 count = nwant;
    595                         else
    596                                 count = tp->nleft;
    597                         memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    598                         tp->nused += count;
    599                         tp->nleft -= count;
    600                         bp += count;
    601                         nwant -= count;
    602                         if (nwant == 0)
    603                                 break;
    604                 }
    605                 if (tp->eof)
    606                         break;
    607 
    608                 /*
    609                  * Wait for the next packet
    610                  */
    611                 retryCount = 0;
    612                 for (;;) {
    613                         int len = getPacket (tp);
    614                         if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    615                                 int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    616                                 rtems_unsigned16 nextBlock = tp->blocknum + 1;
    617                                 if ((opcode == TFTP_OPCODE_DATA)
    618                                  && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    619                                         tp->nused = 0;
    620                                         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    621                                         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    622                                         tp->blocknum++;
    623                                         if (sendAck (tp) != 0)
    624                                                 return RTEMS_IO_ERROR;
    625                                         break;
    626                                 }
    627                                 if (opcode == TFTP_OPCODE_ERROR) {
    628                                         tftpSetErrno (tp);
    629                                         return RTEMS_INTERNAL_ERROR;
    630                                 }
    631                         }
    632 
    633                         /*
    634                          * Keep trying?
    635                          */
    636                         if (++retryCount == IO_RETRY_LIMIT)
    637                                 return RTEMS_IO_ERROR;
    638                         if (sendAck (tp) != 0)
    639                                 return RTEMS_IO_ERROR;
    640                 }
    641         }
    642         ap->bytes_moved = ap->count - nwant;
    643         return RTEMS_SUCCESSFUL;
     649  char              *bp;
     650  struct tftpStream *tp;
     651  int                retryCount;
     652  int                nwant;
     653
     654  tp = iop->data1;
     655
     656  /*
     657   * Read till user request is satisfied or EOF is reached
     658   */
     659
     660  bp = buffer;
     661  nwant = count;
     662  while (nwant) {
     663    if (tp->nleft) {
     664      int count;
     665      if (nwant < tp->nleft)
     666        count = nwant;
     667      else
     668        count = tp->nleft;
     669      memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
     670      tp->nused += count;
     671      tp->nleft -= count;
     672      bp += count;
     673      nwant -= count;
     674      if (nwant == 0)
     675        break;
     676    }
     677    if (tp->eof)
     678      break;
     679
     680    /*
     681     * Wait for the next packet
     682     */
     683    retryCount = 0;
     684    for (;;) {
     685      int len = getPacket (tp);
     686      if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     687        int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     688        rtems_unsigned16 nextBlock = tp->blocknum + 1;
     689        if ((opcode == TFTP_OPCODE_DATA)
     690         && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     691          tp->nused = 0;
     692          tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     693          tp->eof = (tp->nleft < TFTP_BUFSIZE);
     694          tp->blocknum++;
     695          if (sendAck (tp) != 0)
     696            set_errno_and_return_minus_one( EIO );
     697          break;
     698        }
     699        if (opcode == TFTP_OPCODE_ERROR) {
     700          tftpSetErrno (tp);
     701          return RTEMS_INTERNAL_ERROR;
     702        }
     703      }
     704
     705      /*
     706       * Keep trying?
     707       */
     708      if (++retryCount == IO_RETRY_LIMIT)
     709        set_errno_and_return_minus_one( EIO );
     710      if (sendAck (tp) != 0)
     711        set_errno_and_return_minus_one( EIO );
     712    }
     713  }
     714
     715 /*
     716  * XXX - Eric is this right?
     717  *
     718  */
     719  return count - nwant;
    644720}
    645721
     
    647723 * Close a TFTP stream
    648724 */
    649 rtems_device_driver rtems_tftp_close(
    650   rtems_device_major_number major,
    651   rtems_device_minor_number minor,
    652   void *pargp
     725int rtems_tftp_close(
     726  rtems_libio_t *iop
    653727)
    654728{
    655         rtems_libio_open_close_args_t *ap = pargp;
    656         struct tftpStream *tp = ap->iop->data1;;
    657 
    658         if (!tp->eof && !tp->firstReply) {
    659                 /*
    660                  * Tell the other end to stop
    661                  */
    662                 rtems_interval ticksPerSecond;
    663                 sendStifle (tp, &tp->farAddress);
    664                 rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    665                 rtems_task_wake_after (1 + ticksPerSecond / 10);
    666         }
    667         close (tp->socket);
    668         releaseStream (ap->iop->data0);
    669         return RTEMS_SUCCESSFUL;
    670 }
    671 
    672 rtems_device_driver rtems_tftp_write(
    673   rtems_device_major_number major,
    674   rtems_device_minor_number minor,
    675   void *pargp
     729  struct tftpStream *tp = iop->data1;;
     730
     731  if (!tp->eof && !tp->firstReply) {
     732    /*
     733     * Tell the other end to stop
     734     */
     735    rtems_interval ticksPerSecond;
     736    sendStifle (tp, &tp->farAddress);
     737    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     738    rtems_task_wake_after (1 + ticksPerSecond / 10);
     739  }
     740  close (tp->socket);
     741  releaseStream (iop->data0);
     742  return RTEMS_SUCCESSFUL;
     743}
     744
     745int rtems_tftp_write(
     746  rtems_libio_t *iop,
     747  const void    *buffer,
     748  unsigned32     count
    676749)
    677750{
    678         return RTEMS_NOT_CONFIGURED;
     751  return RTEMS_NOT_CONFIGURED;
    679752}
    680753
     
    685758)
    686759{
    687         return RTEMS_NOT_CONFIGURED;
    688 }
     760  return RTEMS_NOT_CONFIGURED;
     761}
     762
     763rtems_filesystem_node_types_t rtems_tftp_node_type(
     764   rtems_filesystem_location_info_t    *pathloc         /* IN */
     765)
     766{
     767  return RTEMS_FILESYSTEM_MEMORY_FILE;
     768}
     769
     770
     771rtems_filesystem_operations_table  rtems_tftp_ops = {
     772  rtems_tftp_eval_path,            /* eval_path */
     773  rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     774  NULL,                            /* link */
     775  NULL,                            /* unlink */
     776  rtems_tftp_node_type,            /* node_type */
     777  NULL,                            /* mknod */
     778  NULL,                            /* rmnod */
     779  NULL,                            /* chown */
     780  NULL,                            /* freenodinfo */
     781  NULL,                            /* mount */
     782  rtems_tftp_mount_me,             /* initialize */
     783  NULL,                            /* unmount */
     784  NULL,                            /* fsunmount */
     785  NULL,                            /* utime, */
     786  NULL,                            /* evaluate_link */
     787  NULL,                            /* symlink */
     788  NULL,                            /* readlin */
     789};
     790
     791rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
     792  rtems_tftp_open,
     793  rtems_tftp_close,
     794  rtems_tftp_read,
     795  rtems_tftp_write,
     796  NULL,
     797  NULL,
     798  NULL,
     799  NULL,
     800  NULL,
     801  NULL,
     802  NULL,
     803  NULL,
     804};
  • c/src/libnetworking/lib/tftpDriver.c

    r7c7fd4d rc1a37d3e  
    1919#include <string.h>
    2020#include <unistd.h>
     21#include <fcntl.h>
    2122#include <rtems.h>
    2223#include <rtems/libio.h>
     
    140141 * Number of streams open at the same time
    141142 */
     143
    142144static rtems_id tftp_mutex;
    143145static int nStreams;
    144146static struct tftpStream ** volatile tftpStreams;
    145147
    146 typedef struct {
    147    rtems_id                             tftp_mutex;
    148    int                                  nStreams;
    149    struct tftpStream ** volatile        tftpStreams;
    150   rtems_filesystem_mount_table_entry_t *mt_entry; 
    151 }  tftp_fs_info;
     148typedef const char *tftp_node;
     149extern rtems_filesystem_operations_table  rtems_tftp_ops;
     150extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;
     151
     152/*
     153 *  Direct copy from the IMFS.  Look at this.
     154 */
     155
     156rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
     157   5,   /* link_max */
     158   6,   /* max_canon */
     159   7,   /* max_input */
     160   255, /* name_max */
     161   255, /* path_max */
     162   2,   /* pipe_buf */
     163   1,   /* posix_async_io */
     164   2,   /* posix_chown_restrictions */
     165   3,   /* posix_no_trunc */
     166   4,   /* posix_prio_io */
     167   5,   /* posix_sync_io */
     168   6    /* posix_vdisable */
     169};
    152170
    153171int rtems_tftp_mount_me(
     
    155173)
    156174{
    157   tftp_fs_info      *fs_info;
    158175  rtems_status_code  sc;
    159176
    160   /*
    161    * Allocate stuff for this file system.
    162    */
    163 
    164   fs_info = calloc( 1, sizeof( tftp_fs_info ));
    165   if ( !fs_info )
    166     set_errno_and_return_minus_one( ENOMEM );
    167 
    168   temp_mt_entry->fs_info                = fs_info;
    169   temp_mt_entry->mt_fs_root.node_access = fs_info;
    170 
     177  temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
     178  temp_mt_entry->mt_fs_root.ops      = &rtems_tftp_ops;
     179
     180  /*
     181   *   We have no tftp filesystem specific data to maintain.  This
     182   *   filesystem may only be mounted ONCE.
     183   *
     184   *   And we maintain no real filesystem nodes, so there is no real root.
     185   */
     186
     187  temp_mt_entry->fs_info                = NULL;
     188  temp_mt_entry->mt_fs_root.node_access = NULL;
     189
     190  /*
     191   *  These need to be looked at for full POSIX semantics.
     192   */
     193
     194  temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
     195
     196
     197  /*
     198   *  Now allocate a semaphore for mutual exclusion.
     199   *
     200   *  NOTE:  This could be in an fsinfo for this filesystem type.
     201   */
    171202 
    172203  sc = rtems_semaphore_create (
     
    179210    RTEMS_LOCAL,
    180211    0,
    181     &fs_info->tftp_mutex
     212    &tftp_mutex
    182213  );
    183214
    184215  if (sc != RTEMS_SUCCESSFUL)
    185     set_errno_and_return_minus_one( ENOMEM ); /* ??? */
     216    set_errno_and_return_minus_one( ENOMEM );
    186217
    187218  return 0;
     
    191222 * Initialize the TFTP driver
    192223 */
    193 /* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
    194 /* XXX this won't be a driver when we are finished */
    195 rtems_device_driver rtems_tftp_initialize(
    196   rtems_device_major_number major,
    197   rtems_device_minor_number minor,
    198   void *pargp
    199 )
    200 {
    201 
    202 /* XXX change to a mount */
    203         rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
    204         return RTEMS_SUCCESSFUL;
     224
     225int rtems_bsdnet_initialize_tftp_filesystem ()
     226{
     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     "RO",
     238     NULL,
     239     TFTP_PATHNAME_PREFIX
     240  );
     241
     242  if ( status )
     243    perror( "TFTP mount failed" );
     244
     245  return status;
    205246}
    206247
     
    339380)
    340381
    341     set_errno_and_return_minus_one( EIO );   
    342 }
     382  set_errno_and_return_minus_one( EIO );   
     383}
     384
    343385/*
    344386 * XXX - Fix return values.
    345387 */
    346388
    347 int TFTP_eval_path( 
     389int rtems_tftp_eval_path( 
    348390  const char                        *pathname,     /* IN     */
    349391  int                                flags,        /* IN     */
     
    351393)
    352394{
    353         rtems_unsigned32 farAddress;
    354         int len;
    355         const char *remoteFilename;
    356 
    357   tftp_fs_info      *fs_info;
    358   const char *cp1, *cp2;
    359 
    360   fs_info = pathloc->node_access;
    361 
    362         /*
    363          * Pick apart the name into a host:pathname pair
    364          */
    365         /*
    366          * XXX - I think this is handled by the caller of
    367          *       the evaluate routine. ? Am I starting at the right
    368          *       place?
    369          */
    370 
    371         cp2 = pathname+1;
    372 
    373         if (*cp2 == '/') {
    374                 farAddress = rtems_bsdnet_bootp_server_address.s_addr;
    375         }
    376         else {
    377                 char *hostname;
    378 
    379                 cp1 = cp2;
    380                 while (*cp2 != '/') {
    381                         if (*cp2 == '\0')
    382                                 return RTEMS_INVALID_NAME;
    383                         cp2++;
    384                 }
    385                 len = cp2 - cp1;
    386                 hostname = malloc (len + 1);
    387                 if (hostname == NULL)
    388                         return RTEMS_NO_MEMORY;
    389                 strncpy (hostname, cp1, len);
    390                 hostname[len] = '\0';
    391                 farAddress = inet_addr (hostname);
    392                 free (hostname);
    393         }
    394         if ((farAddress == 0) || (farAddress == ~0))
    395                 return RTEMS_INVALID_NAME;
    396         if (*++cp2 == '\0')
    397                 return RTEMS_INVALID_NAME;
    398         remoteFilename = cp2;
    399         if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    400                 return RTEMS_INVALID_NAME;
     395
     396  /*
     397   * Read-only for now
     398   */
     399   
     400  if ( (flags & O_WRONLY) == O_WRONLY )
     401    set_errno_and_return_minus_one( ENOENT );
     402
     403  /*
     404   * The File system is mounted at TFTP_PATHNAME_PREFIX
     405   * the caller of this routine has striped off this part of the
     406   * name. Save the remainder of the name for use by the open routine.
     407   */
     408
     409  pathloc->node_access = (void * ) pathname;
     410  pathloc->handlers    = &rtems_tftp_handlers;
    401411
    402412  return 0;
    403413}
    404414
    405 /*
    406  * Open a TFTP stream
    407  */
    408 rtems_device_driver rtems_tftp_open(
    409   rtems_device_major_number major,
    410   rtems_device_minor_number minor,
    411   void *pargp
     415
     416int rtems_tftp_open(
     417  rtems_libio_t *iop,
     418  const char    *new_name,
     419  unsigned32     flag,
     420  unsigned32     mode
    412421)
    413422{
    414         rtems_libio_open_close_args_t *ap = pargp;
    415         struct tftpStream *tp;
    416         int retryCount;
    417         rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
    418         int s;
    419         int len;
    420         char *cp1, *cp2;
    421         char *remoteFilename = NULL; /* XXX - node parameter */
    422         rtems_interval now;
    423         rtems_status_code sc;
    424 
    425         /*
    426          * Read-only for now
    427          */
    428         /* XXX - Move to the open routine */
    429         if (ap->flags & LIBIO_FLAGS_WRITE)
    430                 return RTEMS_NOT_IMPLEMENTED;
    431 
    432 
    433         /*
    434          * Find a free stream
    435          */
    436         sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    437         if (sc != RTEMS_SUCCESSFUL)
    438                 return sc;
    439         for (s = 0 ; s < nStreams ; s++) {
    440                 if (tftpStreams[s] == NULL)
    441                         break;
    442         }
    443         if (s == nStreams) {
    444                 /*
    445                  * Reallocate stream pointers
    446                  * Guard against the case where realloc() returns NULL.
    447                  */
    448                 struct tftpStream **np;
    449 
    450                 np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    451                 if (np == NULL) {
    452                         rtems_semaphore_release (tftp_mutex);
    453                         return RTEMS_NO_MEMORY;
    454                 }
    455                 tftpStreams = np;
    456         }
    457         tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    458         rtems_semaphore_release (tftp_mutex);
    459         if (tp == NULL)
    460                 return RTEMS_NO_MEMORY;
    461         ap->iop->data0 = s;
    462         ap->iop->data1 = tp;
    463 
    464         /*
    465          * Create the socket
    466          */
    467         if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    468                 releaseStream (s);
    469                 return RTEMS_TOO_MANY;
    470         }
    471 
    472         /*
    473          * Bind the socket to a local address
    474          */
    475         retryCount = 0;
    476         rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    477         for (;;) {
    478                 int try = (now + retryCount) % 10;
    479 
    480                 tp->myAddress.sin_family = AF_INET;
    481                 tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
    482                 tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    483                 if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    484                         break;
    485                 if (++retryCount == 10) {
    486                         close (tp->socket);
    487                         releaseStream (minor);
    488                         return RTEMS_RESOURCE_IN_USE;
    489                 }
    490         }
    491 
    492         /*
    493          * Set the UDP destination to the TFTP server
    494          * port on the remote machine.
    495          */
    496         tp->farAddress.sin_family = AF_INET;
    497         tp->farAddress.sin_addr.s_addr = farAddress;
    498         tp->farAddress.sin_port = htons (69);
    499 
    500         /*
    501          * Start the transfer
    502          */
    503         tp->firstReply = 1;
    504         for (;;) {
    505                 /*
    506                  * Create the request
    507                  */
    508                 tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    509                 cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
    510                 cp2 = remoteFilename;
    511                 while ((*cp1++ = *cp2++) != '\0')
    512                         continue;
    513                 cp2 = "octet";
    514                 while ((*cp1++ = *cp2++) != '\0')
    515                         continue;
    516                 len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    517 
    518                 /*
    519                  * Send the request
    520                  */
    521                 if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    522                                         (struct sockaddr *)&tp->farAddress,
    523                                         sizeof tp->farAddress) < 0) {
    524                         close (tp->socket);
    525                         releaseStream (minor);
    526                         return RTEMS_UNSATISFIED;
    527                 }
    528 
    529                 /*
    530                  * Get reply
    531                  */
    532                 len = getPacket (tp);
    533                 if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    534                         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    535                         if ((opcode == TFTP_OPCODE_DATA)
    536                          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    537                                 tp->nused = 0;
    538                                 tp->blocknum = 1;
    539                                 tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    540                                 tp->eof = (tp->nleft < TFTP_BUFSIZE);
    541                                 if (sendAck (tp) != 0) {
    542                                         close (tp->socket);
    543                                         releaseStream (minor);
    544                                         return RTEMS_UNSATISFIED;
    545                                 }
    546                                 break;
    547                         }
    548                         if (opcode == TFTP_OPCODE_ERROR) {
    549                                 tftpSetErrno (tp);
    550                                 close (tp->socket);
    551                                 releaseStream (ap->iop->data0);
    552                                 return RTEMS_INTERNAL_ERROR;
    553                         }
    554                 }
    555 
    556                 /*
    557                  * Keep trying
    558                  */
    559                 if (++retryCount >= OPEN_RETRY_LIMIT) {
    560                         close (tp->socket);
    561                         releaseStream (minor);
    562                         return RTEMS_UNSATISFIED;
    563                 }
    564         }
    565         return RTEMS_SUCCESSFUL;
     423  struct tftpStream  *tp;
     424  int                 retryCount;
     425  rtems_unsigned32    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
     434  /*
     435   * This came from the evaluate path.
     436   */
     437
     438  cp2 = iop->file_info; 
     439  if (*cp2 == '/') {
     440    farAddress = rtems_bsdnet_bootp_server_address.s_addr;
     441  }
     442  else {
     443    char *hostname;
     444
     445    cp1 = cp2;
     446    while (*cp2 != '/') {
     447      if (*cp2 == '\0')
     448        set_errno_and_return_minus_one( ENOENT );
     449       cp2++;
     450    }
     451
     452    len = cp2 - cp1;
     453    hostname = malloc (len + 1);
     454    if (hostname == NULL)
     455      set_errno_and_return_minus_one( ENOMEM );
     456
     457    strncpy (hostname, cp1, len);
     458    hostname[len] = '\0';
     459    farAddress = inet_addr (hostname);
     460    free (hostname);
     461  }
     462
     463  if ((farAddress == 0) || (farAddress == ~0))
     464    set_errno_and_return_minus_one( ENOENT );
     465
     466  if (*++cp2 == '\0')
     467    set_errno_and_return_minus_one( ENOENT );
     468
     469  remoteFilename = cp2;
     470  if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     471    set_errno_and_return_minus_one( ENOENT );
     472
     473  /*
     474   * Find a free stream
     475   */
     476
     477  sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     478  if (sc != RTEMS_SUCCESSFUL)
     479    set_errno_and_return_minus_one( EBUSY );
     480
     481  for (s = 0 ; s < nStreams ; s++) {
     482    if (tftpStreams[s] == NULL)
     483    break;
     484  }
     485
     486  if (s == nStreams) {
     487    /*
     488     * Reallocate stream pointers
     489     * Guard against the case where realloc() returns NULL.
     490     */
     491    struct tftpStream **np;
     492
     493    np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     494    if (np == NULL) {
     495      rtems_semaphore_release (tftp_mutex);
     496      set_errno_and_return_minus_one( ENOMEM );
     497    }
     498    tftpStreams = np;
     499  }
     500
     501  tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     502  rtems_semaphore_release (tftp_mutex);
     503  if (tp == NULL)
     504    set_errno_and_return_minus_one( ENOMEM );
     505  iop->data0 = s;
     506  iop->data1 = tp;
     507
     508  /*
     509   * Create the socket
     510   */
     511
     512  if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
     513    releaseStream (s);
     514    set_errno_and_return_minus_one( ENOMEM );
     515  }
     516
     517  /*
     518   * Bind the socket to a local address
     519   */
     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    /*
     528     *  XXX Eric .. how do we get the minor information???
     529     * tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
     530     */
     531    tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
     532    tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     533    if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     534      break;
     535    if (++retryCount == 10) {
     536      close (tp->socket);
     537      /*
     538       *  XXX Eric .. how do we get the minor information to release this???
     539        releaseStream (minor);
     540       */
     541      set_errno_and_return_minus_one( EBUSY );
     542    }
     543  }
     544
     545  /*
     546   * Set the UDP destination to the TFTP server
     547   * port on the remote machine.
     548   */
     549  tp->farAddress.sin_family = AF_INET;
     550  tp->farAddress.sin_addr.s_addr = farAddress;
     551  tp->farAddress.sin_port = htons (69);
     552
     553  /*
     554   * Start the transfer
     555   */
     556  tp->firstReply = 1;
     557  for (;;) {
     558    /*
     559     * Create the request
     560     */
     561    tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     562      /*
     563       *  XXX Eric .. is this cast taking the const off right?
     564       */
     565
     566    cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     567    cp2 = (char *) remoteFilename;
     568    while ((*cp1++ = *cp2++) != '\0')
     569      continue;
     570    cp2 = "octet";
     571    while ((*cp1++ = *cp2++) != '\0')
     572      continue;
     573    len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     574
     575    /*
     576     * Send the request
     577     */
     578    if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     579          (struct sockaddr *)&tp->farAddress,
     580          sizeof tp->farAddress) < 0) {
     581      close (tp->socket);
     582      /*
     583       *  XXX Eric .. how do we get the minor information to release this???
     584        releaseStream (minor);
     585       */
     586      set_errno_and_return_minus_one( EIO );
     587    }
     588
     589    /*
     590     * Get reply
     591     */
     592    len = getPacket (tp);
     593    if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     594      int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     595      if ((opcode == TFTP_OPCODE_DATA)
     596       && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     597        tp->nused = 0;
     598        tp->blocknum = 1;
     599        tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     600        tp->eof = (tp->nleft < TFTP_BUFSIZE);
     601        if (sendAck (tp) != 0) {
     602          close (tp->socket);
     603      /*
     604       *  XXX Eric .. how do we get the minor information to release this???
     605          releaseStream (minor);
     606       */
     607
     608          set_errno_and_return_minus_one( EIO );
     609        }
     610        break;
     611      }
     612      if (opcode == TFTP_OPCODE_ERROR) {
     613        tftpSetErrno (tp);
     614        close (tp->socket);
     615      /*
     616       *  XXX Eric .. how do we get the minor information to release this???
     617       *  releaseStream (minor);
     618       */
     619        set_errno_and_return_minus_one( EIO );
     620      }
     621    }
     622
     623    /*
     624     * Keep trying
     625     */
     626    if (++retryCount >= OPEN_RETRY_LIMIT) {
     627      close (tp->socket);
     628      /*
     629       *  XXX Eric .. how do we get the minor information to release this???
     630        releaseStream (minor);
     631       */
     632      set_errno_and_return_minus_one( EIO );
     633    }
     634  }
     635
     636  return 0;
    566637}
    567638
     
    569640 * Read from a TFTP stream
    570641 */
    571 rtems_device_driver rtems_tftp_read(
    572   rtems_device_major_number major,
    573   rtems_device_minor_number minor,
    574   void *pargp
     642
     643int rtems_tftp_read(
     644  rtems_libio_t *iop,
     645  void          *buffer,
     646  unsigned32     count
    575647)
    576648{
    577         rtems_libio_rw_args_t *ap = pargp;
    578         char *bp;
    579         struct tftpStream *tp;
    580         int retryCount;
    581         int nwant;
    582 
    583         tp = ap->iop->data1;
    584 
    585         /*
    586          * Read till user request is satisfied or EOF is reached
    587          */
    588         bp = ap->buffer;
    589         nwant = ap->count;
    590         while (nwant) {
    591                 if (tp->nleft) {
    592                         int count;
    593                         if (nwant < tp->nleft)
    594                                 count = nwant;
    595                         else
    596                                 count = tp->nleft;
    597                         memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    598                         tp->nused += count;
    599                         tp->nleft -= count;
    600                         bp += count;
    601                         nwant -= count;
    602                         if (nwant == 0)
    603                                 break;
    604                 }
    605                 if (tp->eof)
    606                         break;
    607 
    608                 /*
    609                  * Wait for the next packet
    610                  */
    611                 retryCount = 0;
    612                 for (;;) {
    613                         int len = getPacket (tp);
    614                         if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    615                                 int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    616                                 rtems_unsigned16 nextBlock = tp->blocknum + 1;
    617                                 if ((opcode == TFTP_OPCODE_DATA)
    618                                  && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    619                                         tp->nused = 0;
    620                                         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    621                                         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    622                                         tp->blocknum++;
    623                                         if (sendAck (tp) != 0)
    624                                                 return RTEMS_IO_ERROR;
    625                                         break;
    626                                 }
    627                                 if (opcode == TFTP_OPCODE_ERROR) {
    628                                         tftpSetErrno (tp);
    629                                         return RTEMS_INTERNAL_ERROR;
    630                                 }
    631                         }
    632 
    633                         /*
    634                          * Keep trying?
    635                          */
    636                         if (++retryCount == IO_RETRY_LIMIT)
    637                                 return RTEMS_IO_ERROR;
    638                         if (sendAck (tp) != 0)
    639                                 return RTEMS_IO_ERROR;
    640                 }
    641         }
    642         ap->bytes_moved = ap->count - nwant;
    643         return RTEMS_SUCCESSFUL;
     649  char              *bp;
     650  struct tftpStream *tp;
     651  int                retryCount;
     652  int                nwant;
     653
     654  tp = iop->data1;
     655
     656  /*
     657   * Read till user request is satisfied or EOF is reached
     658   */
     659
     660  bp = buffer;
     661  nwant = count;
     662  while (nwant) {
     663    if (tp->nleft) {
     664      int count;
     665      if (nwant < tp->nleft)
     666        count = nwant;
     667      else
     668        count = tp->nleft;
     669      memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
     670      tp->nused += count;
     671      tp->nleft -= count;
     672      bp += count;
     673      nwant -= count;
     674      if (nwant == 0)
     675        break;
     676    }
     677    if (tp->eof)
     678      break;
     679
     680    /*
     681     * Wait for the next packet
     682     */
     683    retryCount = 0;
     684    for (;;) {
     685      int len = getPacket (tp);
     686      if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     687        int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     688        rtems_unsigned16 nextBlock = tp->blocknum + 1;
     689        if ((opcode == TFTP_OPCODE_DATA)
     690         && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     691          tp->nused = 0;
     692          tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     693          tp->eof = (tp->nleft < TFTP_BUFSIZE);
     694          tp->blocknum++;
     695          if (sendAck (tp) != 0)
     696            set_errno_and_return_minus_one( EIO );
     697          break;
     698        }
     699        if (opcode == TFTP_OPCODE_ERROR) {
     700          tftpSetErrno (tp);
     701          return RTEMS_INTERNAL_ERROR;
     702        }
     703      }
     704
     705      /*
     706       * Keep trying?
     707       */
     708      if (++retryCount == IO_RETRY_LIMIT)
     709        set_errno_and_return_minus_one( EIO );
     710      if (sendAck (tp) != 0)
     711        set_errno_and_return_minus_one( EIO );
     712    }
     713  }
     714
     715 /*
     716  * XXX - Eric is this right?
     717  *
     718  */
     719  return count - nwant;
    644720}
    645721
     
    647723 * Close a TFTP stream
    648724 */
    649 rtems_device_driver rtems_tftp_close(
    650   rtems_device_major_number major,
    651   rtems_device_minor_number minor,
    652   void *pargp
     725int rtems_tftp_close(
     726  rtems_libio_t *iop
    653727)
    654728{
    655         rtems_libio_open_close_args_t *ap = pargp;
    656         struct tftpStream *tp = ap->iop->data1;;
    657 
    658         if (!tp->eof && !tp->firstReply) {
    659                 /*
    660                  * Tell the other end to stop
    661                  */
    662                 rtems_interval ticksPerSecond;
    663                 sendStifle (tp, &tp->farAddress);
    664                 rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    665                 rtems_task_wake_after (1 + ticksPerSecond / 10);
    666         }
    667         close (tp->socket);
    668         releaseStream (ap->iop->data0);
    669         return RTEMS_SUCCESSFUL;
    670 }
    671 
    672 rtems_device_driver rtems_tftp_write(
    673   rtems_device_major_number major,
    674   rtems_device_minor_number minor,
    675   void *pargp
     729  struct tftpStream *tp = iop->data1;;
     730
     731  if (!tp->eof && !tp->firstReply) {
     732    /*
     733     * Tell the other end to stop
     734     */
     735    rtems_interval ticksPerSecond;
     736    sendStifle (tp, &tp->farAddress);
     737    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     738    rtems_task_wake_after (1 + ticksPerSecond / 10);
     739  }
     740  close (tp->socket);
     741  releaseStream (iop->data0);
     742  return RTEMS_SUCCESSFUL;
     743}
     744
     745int rtems_tftp_write(
     746  rtems_libio_t *iop,
     747  const void    *buffer,
     748  unsigned32     count
    676749)
    677750{
    678         return RTEMS_NOT_CONFIGURED;
     751  return RTEMS_NOT_CONFIGURED;
    679752}
    680753
     
    685758)
    686759{
    687         return RTEMS_NOT_CONFIGURED;
    688 }
     760  return RTEMS_NOT_CONFIGURED;
     761}
     762
     763rtems_filesystem_node_types_t rtems_tftp_node_type(
     764   rtems_filesystem_location_info_t    *pathloc         /* IN */
     765)
     766{
     767  return RTEMS_FILESYSTEM_MEMORY_FILE;
     768}
     769
     770
     771rtems_filesystem_operations_table  rtems_tftp_ops = {
     772  rtems_tftp_eval_path,            /* eval_path */
     773  rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     774  NULL,                            /* link */
     775  NULL,                            /* unlink */
     776  rtems_tftp_node_type,            /* node_type */
     777  NULL,                            /* mknod */
     778  NULL,                            /* rmnod */
     779  NULL,                            /* chown */
     780  NULL,                            /* freenodinfo */
     781  NULL,                            /* mount */
     782  rtems_tftp_mount_me,             /* initialize */
     783  NULL,                            /* unmount */
     784  NULL,                            /* fsunmount */
     785  NULL,                            /* utime, */
     786  NULL,                            /* evaluate_link */
     787  NULL,                            /* symlink */
     788  NULL,                            /* readlin */
     789};
     790
     791rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
     792  rtems_tftp_open,
     793  rtems_tftp_close,
     794  rtems_tftp_read,
     795  rtems_tftp_write,
     796  NULL,
     797  NULL,
     798  NULL,
     799  NULL,
     800  NULL,
     801  NULL,
     802  NULL,
     803  NULL,
     804};
  • cpukit/libnetworking/lib/tftpDriver.c

    r7c7fd4d rc1a37d3e  
    1919#include <string.h>
    2020#include <unistd.h>
     21#include <fcntl.h>
    2122#include <rtems.h>
    2223#include <rtems/libio.h>
     
    140141 * Number of streams open at the same time
    141142 */
     143
    142144static rtems_id tftp_mutex;
    143145static int nStreams;
    144146static struct tftpStream ** volatile tftpStreams;
    145147
    146 typedef struct {
    147    rtems_id                             tftp_mutex;
    148    int                                  nStreams;
    149    struct tftpStream ** volatile        tftpStreams;
    150   rtems_filesystem_mount_table_entry_t *mt_entry; 
    151 }  tftp_fs_info;
     148typedef const char *tftp_node;
     149extern rtems_filesystem_operations_table  rtems_tftp_ops;
     150extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;
     151
     152/*
     153 *  Direct copy from the IMFS.  Look at this.
     154 */
     155
     156rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
     157   5,   /* link_max */
     158   6,   /* max_canon */
     159   7,   /* max_input */
     160   255, /* name_max */
     161   255, /* path_max */
     162   2,   /* pipe_buf */
     163   1,   /* posix_async_io */
     164   2,   /* posix_chown_restrictions */
     165   3,   /* posix_no_trunc */
     166   4,   /* posix_prio_io */
     167   5,   /* posix_sync_io */
     168   6    /* posix_vdisable */
     169};
    152170
    153171int rtems_tftp_mount_me(
     
    155173)
    156174{
    157   tftp_fs_info      *fs_info;
    158175  rtems_status_code  sc;
    159176
    160   /*
    161    * Allocate stuff for this file system.
    162    */
    163 
    164   fs_info = calloc( 1, sizeof( tftp_fs_info ));
    165   if ( !fs_info )
    166     set_errno_and_return_minus_one( ENOMEM );
    167 
    168   temp_mt_entry->fs_info                = fs_info;
    169   temp_mt_entry->mt_fs_root.node_access = fs_info;
    170 
     177  temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
     178  temp_mt_entry->mt_fs_root.ops      = &rtems_tftp_ops;
     179
     180  /*
     181   *   We have no tftp filesystem specific data to maintain.  This
     182   *   filesystem may only be mounted ONCE.
     183   *
     184   *   And we maintain no real filesystem nodes, so there is no real root.
     185   */
     186
     187  temp_mt_entry->fs_info                = NULL;
     188  temp_mt_entry->mt_fs_root.node_access = NULL;
     189
     190  /*
     191   *  These need to be looked at for full POSIX semantics.
     192   */
     193
     194  temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
     195
     196
     197  /*
     198   *  Now allocate a semaphore for mutual exclusion.
     199   *
     200   *  NOTE:  This could be in an fsinfo for this filesystem type.
     201   */
    171202 
    172203  sc = rtems_semaphore_create (
     
    179210    RTEMS_LOCAL,
    180211    0,
    181     &fs_info->tftp_mutex
     212    &tftp_mutex
    182213  );
    183214
    184215  if (sc != RTEMS_SUCCESSFUL)
    185     set_errno_and_return_minus_one( ENOMEM ); /* ??? */
     216    set_errno_and_return_minus_one( ENOMEM );
    186217
    187218  return 0;
     
    191222 * Initialize the TFTP driver
    192223 */
    193 /* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
    194 /* XXX this won't be a driver when we are finished */
    195 rtems_device_driver rtems_tftp_initialize(
    196   rtems_device_major_number major,
    197   rtems_device_minor_number minor,
    198   void *pargp
    199 )
    200 {
    201 
    202 /* XXX change to a mount */
    203         rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
    204         return RTEMS_SUCCESSFUL;
     224
     225int rtems_bsdnet_initialize_tftp_filesystem ()
     226{
     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     "RO",
     238     NULL,
     239     TFTP_PATHNAME_PREFIX
     240  );
     241
     242  if ( status )
     243    perror( "TFTP mount failed" );
     244
     245  return status;
    205246}
    206247
     
    339380)
    340381
    341     set_errno_and_return_minus_one( EIO );   
    342 }
     382  set_errno_and_return_minus_one( EIO );   
     383}
     384
    343385/*
    344386 * XXX - Fix return values.
    345387 */
    346388
    347 int TFTP_eval_path( 
     389int rtems_tftp_eval_path( 
    348390  const char                        *pathname,     /* IN     */
    349391  int                                flags,        /* IN     */
     
    351393)
    352394{
    353         rtems_unsigned32 farAddress;
    354         int len;
    355         const char *remoteFilename;
    356 
    357   tftp_fs_info      *fs_info;
    358   const char *cp1, *cp2;
    359 
    360   fs_info = pathloc->node_access;
    361 
    362         /*
    363          * Pick apart the name into a host:pathname pair
    364          */
    365         /*
    366          * XXX - I think this is handled by the caller of
    367          *       the evaluate routine. ? Am I starting at the right
    368          *       place?
    369          */
    370 
    371         cp2 = pathname+1;
    372 
    373         if (*cp2 == '/') {
    374                 farAddress = rtems_bsdnet_bootp_server_address.s_addr;
    375         }
    376         else {
    377                 char *hostname;
    378 
    379                 cp1 = cp2;
    380                 while (*cp2 != '/') {
    381                         if (*cp2 == '\0')
    382                                 return RTEMS_INVALID_NAME;
    383                         cp2++;
    384                 }
    385                 len = cp2 - cp1;
    386                 hostname = malloc (len + 1);
    387                 if (hostname == NULL)
    388                         return RTEMS_NO_MEMORY;
    389                 strncpy (hostname, cp1, len);
    390                 hostname[len] = '\0';
    391                 farAddress = inet_addr (hostname);
    392                 free (hostname);
    393         }
    394         if ((farAddress == 0) || (farAddress == ~0))
    395                 return RTEMS_INVALID_NAME;
    396         if (*++cp2 == '\0')
    397                 return RTEMS_INVALID_NAME;
    398         remoteFilename = cp2;
    399         if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
    400                 return RTEMS_INVALID_NAME;
     395
     396  /*
     397   * Read-only for now
     398   */
     399   
     400  if ( (flags & O_WRONLY) == O_WRONLY )
     401    set_errno_and_return_minus_one( ENOENT );
     402
     403  /*
     404   * The File system is mounted at TFTP_PATHNAME_PREFIX
     405   * the caller of this routine has striped off this part of the
     406   * name. Save the remainder of the name for use by the open routine.
     407   */
     408
     409  pathloc->node_access = (void * ) pathname;
     410  pathloc->handlers    = &rtems_tftp_handlers;
    401411
    402412  return 0;
    403413}
    404414
    405 /*
    406  * Open a TFTP stream
    407  */
    408 rtems_device_driver rtems_tftp_open(
    409   rtems_device_major_number major,
    410   rtems_device_minor_number minor,
    411   void *pargp
     415
     416int rtems_tftp_open(
     417  rtems_libio_t *iop,
     418  const char    *new_name,
     419  unsigned32     flag,
     420  unsigned32     mode
    412421)
    413422{
    414         rtems_libio_open_close_args_t *ap = pargp;
    415         struct tftpStream *tp;
    416         int retryCount;
    417         rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
    418         int s;
    419         int len;
    420         char *cp1, *cp2;
    421         char *remoteFilename = NULL; /* XXX - node parameter */
    422         rtems_interval now;
    423         rtems_status_code sc;
    424 
    425         /*
    426          * Read-only for now
    427          */
    428         /* XXX - Move to the open routine */
    429         if (ap->flags & LIBIO_FLAGS_WRITE)
    430                 return RTEMS_NOT_IMPLEMENTED;
    431 
    432 
    433         /*
    434          * Find a free stream
    435          */
    436         sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    437         if (sc != RTEMS_SUCCESSFUL)
    438                 return sc;
    439         for (s = 0 ; s < nStreams ; s++) {
    440                 if (tftpStreams[s] == NULL)
    441                         break;
    442         }
    443         if (s == nStreams) {
    444                 /*
    445                  * Reallocate stream pointers
    446                  * Guard against the case where realloc() returns NULL.
    447                  */
    448                 struct tftpStream **np;
    449 
    450                 np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
    451                 if (np == NULL) {
    452                         rtems_semaphore_release (tftp_mutex);
    453                         return RTEMS_NO_MEMORY;
    454                 }
    455                 tftpStreams = np;
    456         }
    457         tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
    458         rtems_semaphore_release (tftp_mutex);
    459         if (tp == NULL)
    460                 return RTEMS_NO_MEMORY;
    461         ap->iop->data0 = s;
    462         ap->iop->data1 = tp;
    463 
    464         /*
    465          * Create the socket
    466          */
    467         if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
    468                 releaseStream (s);
    469                 return RTEMS_TOO_MANY;
    470         }
    471 
    472         /*
    473          * Bind the socket to a local address
    474          */
    475         retryCount = 0;
    476         rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
    477         for (;;) {
    478                 int try = (now + retryCount) % 10;
    479 
    480                 tp->myAddress.sin_family = AF_INET;
    481                 tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
    482                 tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
    483                 if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
    484                         break;
    485                 if (++retryCount == 10) {
    486                         close (tp->socket);
    487                         releaseStream (minor);
    488                         return RTEMS_RESOURCE_IN_USE;
    489                 }
    490         }
    491 
    492         /*
    493          * Set the UDP destination to the TFTP server
    494          * port on the remote machine.
    495          */
    496         tp->farAddress.sin_family = AF_INET;
    497         tp->farAddress.sin_addr.s_addr = farAddress;
    498         tp->farAddress.sin_port = htons (69);
    499 
    500         /*
    501          * Start the transfer
    502          */
    503         tp->firstReply = 1;
    504         for (;;) {
    505                 /*
    506                  * Create the request
    507                  */
    508                 tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
    509                 cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
    510                 cp2 = remoteFilename;
    511                 while ((*cp1++ = *cp2++) != '\0')
    512                         continue;
    513                 cp2 = "octet";
    514                 while ((*cp1++ = *cp2++) != '\0')
    515                         continue;
    516                 len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
    517 
    518                 /*
    519                  * Send the request
    520                  */
    521                 if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
    522                                         (struct sockaddr *)&tp->farAddress,
    523                                         sizeof tp->farAddress) < 0) {
    524                         close (tp->socket);
    525                         releaseStream (minor);
    526                         return RTEMS_UNSATISFIED;
    527                 }
    528 
    529                 /*
    530                  * Get reply
    531                  */
    532                 len = getPacket (tp);
    533                 if (len >= (int) sizeof tp->pkbuf.tftpACK) {
    534                         int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    535                         if ((opcode == TFTP_OPCODE_DATA)
    536                          && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
    537                                 tp->nused = 0;
    538                                 tp->blocknum = 1;
    539                                 tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    540                                 tp->eof = (tp->nleft < TFTP_BUFSIZE);
    541                                 if (sendAck (tp) != 0) {
    542                                         close (tp->socket);
    543                                         releaseStream (minor);
    544                                         return RTEMS_UNSATISFIED;
    545                                 }
    546                                 break;
    547                         }
    548                         if (opcode == TFTP_OPCODE_ERROR) {
    549                                 tftpSetErrno (tp);
    550                                 close (tp->socket);
    551                                 releaseStream (ap->iop->data0);
    552                                 return RTEMS_INTERNAL_ERROR;
    553                         }
    554                 }
    555 
    556                 /*
    557                  * Keep trying
    558                  */
    559                 if (++retryCount >= OPEN_RETRY_LIMIT) {
    560                         close (tp->socket);
    561                         releaseStream (minor);
    562                         return RTEMS_UNSATISFIED;
    563                 }
    564         }
    565         return RTEMS_SUCCESSFUL;
     423  struct tftpStream  *tp;
     424  int                 retryCount;
     425  rtems_unsigned32    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
     434  /*
     435   * This came from the evaluate path.
     436   */
     437
     438  cp2 = iop->file_info; 
     439  if (*cp2 == '/') {
     440    farAddress = rtems_bsdnet_bootp_server_address.s_addr;
     441  }
     442  else {
     443    char *hostname;
     444
     445    cp1 = cp2;
     446    while (*cp2 != '/') {
     447      if (*cp2 == '\0')
     448        set_errno_and_return_minus_one( ENOENT );
     449       cp2++;
     450    }
     451
     452    len = cp2 - cp1;
     453    hostname = malloc (len + 1);
     454    if (hostname == NULL)
     455      set_errno_and_return_minus_one( ENOMEM );
     456
     457    strncpy (hostname, cp1, len);
     458    hostname[len] = '\0';
     459    farAddress = inet_addr (hostname);
     460    free (hostname);
     461  }
     462
     463  if ((farAddress == 0) || (farAddress == ~0))
     464    set_errno_and_return_minus_one( ENOENT );
     465
     466  if (*++cp2 == '\0')
     467    set_errno_and_return_minus_one( ENOENT );
     468
     469  remoteFilename = cp2;
     470  if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
     471    set_errno_and_return_minus_one( ENOENT );
     472
     473  /*
     474   * Find a free stream
     475   */
     476
     477  sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     478  if (sc != RTEMS_SUCCESSFUL)
     479    set_errno_and_return_minus_one( EBUSY );
     480
     481  for (s = 0 ; s < nStreams ; s++) {
     482    if (tftpStreams[s] == NULL)
     483    break;
     484  }
     485
     486  if (s == nStreams) {
     487    /*
     488     * Reallocate stream pointers
     489     * Guard against the case where realloc() returns NULL.
     490     */
     491    struct tftpStream **np;
     492
     493    np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
     494    if (np == NULL) {
     495      rtems_semaphore_release (tftp_mutex);
     496      set_errno_and_return_minus_one( ENOMEM );
     497    }
     498    tftpStreams = np;
     499  }
     500
     501  tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
     502  rtems_semaphore_release (tftp_mutex);
     503  if (tp == NULL)
     504    set_errno_and_return_minus_one( ENOMEM );
     505  iop->data0 = s;
     506  iop->data1 = tp;
     507
     508  /*
     509   * Create the socket
     510   */
     511
     512  if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
     513    releaseStream (s);
     514    set_errno_and_return_minus_one( ENOMEM );
     515  }
     516
     517  /*
     518   * Bind the socket to a local address
     519   */
     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    /*
     528     *  XXX Eric .. how do we get the minor information???
     529     * tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
     530     */
     531    tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
     532    tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
     533    if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
     534      break;
     535    if (++retryCount == 10) {
     536      close (tp->socket);
     537      /*
     538       *  XXX Eric .. how do we get the minor information to release this???
     539        releaseStream (minor);
     540       */
     541      set_errno_and_return_minus_one( EBUSY );
     542    }
     543  }
     544
     545  /*
     546   * Set the UDP destination to the TFTP server
     547   * port on the remote machine.
     548   */
     549  tp->farAddress.sin_family = AF_INET;
     550  tp->farAddress.sin_addr.s_addr = farAddress;
     551  tp->farAddress.sin_port = htons (69);
     552
     553  /*
     554   * Start the transfer
     555   */
     556  tp->firstReply = 1;
     557  for (;;) {
     558    /*
     559     * Create the request
     560     */
     561    tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
     562      /*
     563       *  XXX Eric .. is this cast taking the const off right?
     564       */
     565
     566    cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
     567    cp2 = (char *) remoteFilename;
     568    while ((*cp1++ = *cp2++) != '\0')
     569      continue;
     570    cp2 = "octet";
     571    while ((*cp1++ = *cp2++) != '\0')
     572      continue;
     573    len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
     574
     575    /*
     576     * Send the request
     577     */
     578    if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
     579          (struct sockaddr *)&tp->farAddress,
     580          sizeof tp->farAddress) < 0) {
     581      close (tp->socket);
     582      /*
     583       *  XXX Eric .. how do we get the minor information to release this???
     584        releaseStream (minor);
     585       */
     586      set_errno_and_return_minus_one( EIO );
     587    }
     588
     589    /*
     590     * Get reply
     591     */
     592    len = getPacket (tp);
     593    if (len >= (int) sizeof tp->pkbuf.tftpACK) {
     594      int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     595      if ((opcode == TFTP_OPCODE_DATA)
     596       && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
     597        tp->nused = 0;
     598        tp->blocknum = 1;
     599        tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     600        tp->eof = (tp->nleft < TFTP_BUFSIZE);
     601        if (sendAck (tp) != 0) {
     602          close (tp->socket);
     603      /*
     604       *  XXX Eric .. how do we get the minor information to release this???
     605          releaseStream (minor);
     606       */
     607
     608          set_errno_and_return_minus_one( EIO );
     609        }
     610        break;
     611      }
     612      if (opcode == TFTP_OPCODE_ERROR) {
     613        tftpSetErrno (tp);
     614        close (tp->socket);
     615      /*
     616       *  XXX Eric .. how do we get the minor information to release this???
     617       *  releaseStream (minor);
     618       */
     619        set_errno_and_return_minus_one( EIO );
     620      }
     621    }
     622
     623    /*
     624     * Keep trying
     625     */
     626    if (++retryCount >= OPEN_RETRY_LIMIT) {
     627      close (tp->socket);
     628      /*
     629       *  XXX Eric .. how do we get the minor information to release this???
     630        releaseStream (minor);
     631       */
     632      set_errno_and_return_minus_one( EIO );
     633    }
     634  }
     635
     636  return 0;
    566637}
    567638
     
    569640 * Read from a TFTP stream
    570641 */
    571 rtems_device_driver rtems_tftp_read(
    572   rtems_device_major_number major,
    573   rtems_device_minor_number minor,
    574   void *pargp
     642
     643int rtems_tftp_read(
     644  rtems_libio_t *iop,
     645  void          *buffer,
     646  unsigned32     count
    575647)
    576648{
    577         rtems_libio_rw_args_t *ap = pargp;
    578         char *bp;
    579         struct tftpStream *tp;
    580         int retryCount;
    581         int nwant;
    582 
    583         tp = ap->iop->data1;
    584 
    585         /*
    586          * Read till user request is satisfied or EOF is reached
    587          */
    588         bp = ap->buffer;
    589         nwant = ap->count;
    590         while (nwant) {
    591                 if (tp->nleft) {
    592                         int count;
    593                         if (nwant < tp->nleft)
    594                                 count = nwant;
    595                         else
    596                                 count = tp->nleft;
    597                         memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
    598                         tp->nused += count;
    599                         tp->nleft -= count;
    600                         bp += count;
    601                         nwant -= count;
    602                         if (nwant == 0)
    603                                 break;
    604                 }
    605                 if (tp->eof)
    606                         break;
    607 
    608                 /*
    609                  * Wait for the next packet
    610                  */
    611                 retryCount = 0;
    612                 for (;;) {
    613                         int len = getPacket (tp);
    614                         if (len >= (int)sizeof tp->pkbuf.tftpACK) {
    615                                 int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
    616                                 rtems_unsigned16 nextBlock = tp->blocknum + 1;
    617                                 if ((opcode == TFTP_OPCODE_DATA)
    618                                  && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
    619                                         tp->nused = 0;
    620                                         tp->nleft = len - 2 * sizeof (rtems_unsigned16);
    621                                         tp->eof = (tp->nleft < TFTP_BUFSIZE);
    622                                         tp->blocknum++;
    623                                         if (sendAck (tp) != 0)
    624                                                 return RTEMS_IO_ERROR;
    625                                         break;
    626                                 }
    627                                 if (opcode == TFTP_OPCODE_ERROR) {
    628                                         tftpSetErrno (tp);
    629                                         return RTEMS_INTERNAL_ERROR;
    630                                 }
    631                         }
    632 
    633                         /*
    634                          * Keep trying?
    635                          */
    636                         if (++retryCount == IO_RETRY_LIMIT)
    637                                 return RTEMS_IO_ERROR;
    638                         if (sendAck (tp) != 0)
    639                                 return RTEMS_IO_ERROR;
    640                 }
    641         }
    642         ap->bytes_moved = ap->count - nwant;
    643         return RTEMS_SUCCESSFUL;
     649  char              *bp;
     650  struct tftpStream *tp;
     651  int                retryCount;
     652  int                nwant;
     653
     654  tp = iop->data1;
     655
     656  /*
     657   * Read till user request is satisfied or EOF is reached
     658   */
     659
     660  bp = buffer;
     661  nwant = count;
     662  while (nwant) {
     663    if (tp->nleft) {
     664      int count;
     665      if (nwant < tp->nleft)
     666        count = nwant;
     667      else
     668        count = tp->nleft;
     669      memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
     670      tp->nused += count;
     671      tp->nleft -= count;
     672      bp += count;
     673      nwant -= count;
     674      if (nwant == 0)
     675        break;
     676    }
     677    if (tp->eof)
     678      break;
     679
     680    /*
     681     * Wait for the next packet
     682     */
     683    retryCount = 0;
     684    for (;;) {
     685      int len = getPacket (tp);
     686      if (len >= (int)sizeof tp->pkbuf.tftpACK) {
     687        int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
     688        rtems_unsigned16 nextBlock = tp->blocknum + 1;
     689        if ((opcode == TFTP_OPCODE_DATA)
     690         && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
     691          tp->nused = 0;
     692          tp->nleft = len - 2 * sizeof (rtems_unsigned16);
     693          tp->eof = (tp->nleft < TFTP_BUFSIZE);
     694          tp->blocknum++;
     695          if (sendAck (tp) != 0)
     696            set_errno_and_return_minus_one( EIO );
     697          break;
     698        }
     699        if (opcode == TFTP_OPCODE_ERROR) {
     700          tftpSetErrno (tp);
     701          return RTEMS_INTERNAL_ERROR;
     702        }
     703      }
     704
     705      /*
     706       * Keep trying?
     707       */
     708      if (++retryCount == IO_RETRY_LIMIT)
     709        set_errno_and_return_minus_one( EIO );
     710      if (sendAck (tp) != 0)
     711        set_errno_and_return_minus_one( EIO );
     712    }
     713  }
     714
     715 /*
     716  * XXX - Eric is this right?
     717  *
     718  */
     719  return count - nwant;
    644720}
    645721
     
    647723 * Close a TFTP stream
    648724 */
    649 rtems_device_driver rtems_tftp_close(
    650   rtems_device_major_number major,
    651   rtems_device_minor_number minor,
    652   void *pargp
     725int rtems_tftp_close(
     726  rtems_libio_t *iop
    653727)
    654728{
    655         rtems_libio_open_close_args_t *ap = pargp;
    656         struct tftpStream *tp = ap->iop->data1;;
    657 
    658         if (!tp->eof && !tp->firstReply) {
    659                 /*
    660                  * Tell the other end to stop
    661                  */
    662                 rtems_interval ticksPerSecond;
    663                 sendStifle (tp, &tp->farAddress);
    664                 rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
    665                 rtems_task_wake_after (1 + ticksPerSecond / 10);
    666         }
    667         close (tp->socket);
    668         releaseStream (ap->iop->data0);
    669         return RTEMS_SUCCESSFUL;
    670 }
    671 
    672 rtems_device_driver rtems_tftp_write(
    673   rtems_device_major_number major,
    674   rtems_device_minor_number minor,
    675   void *pargp
     729  struct tftpStream *tp = iop->data1;;
     730
     731  if (!tp->eof && !tp->firstReply) {
     732    /*
     733     * Tell the other end to stop
     734     */
     735    rtems_interval ticksPerSecond;
     736    sendStifle (tp, &tp->farAddress);
     737    rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
     738    rtems_task_wake_after (1 + ticksPerSecond / 10);
     739  }
     740  close (tp->socket);
     741  releaseStream (iop->data0);
     742  return RTEMS_SUCCESSFUL;
     743}
     744
     745int rtems_tftp_write(
     746  rtems_libio_t *iop,
     747  const void    *buffer,
     748  unsigned32     count
    676749)
    677750{
    678         return RTEMS_NOT_CONFIGURED;
     751  return RTEMS_NOT_CONFIGURED;
    679752}
    680753
     
    685758)
    686759{
    687         return RTEMS_NOT_CONFIGURED;
    688 }
     760  return RTEMS_NOT_CONFIGURED;
     761}
     762
     763rtems_filesystem_node_types_t rtems_tftp_node_type(
     764   rtems_filesystem_location_info_t    *pathloc         /* IN */
     765)
     766{
     767  return RTEMS_FILESYSTEM_MEMORY_FILE;
     768}
     769
     770
     771rtems_filesystem_operations_table  rtems_tftp_ops = {
     772  rtems_tftp_eval_path,            /* eval_path */
     773  rtems_tftp_evaluate_for_make,    /* evaluate_for_make */
     774  NULL,                            /* link */
     775  NULL,                            /* unlink */
     776  rtems_tftp_node_type,            /* node_type */
     777  NULL,                            /* mknod */
     778  NULL,                            /* rmnod */
     779  NULL,                            /* chown */
     780  NULL,                            /* freenodinfo */
     781  NULL,                            /* mount */
     782  rtems_tftp_mount_me,             /* initialize */
     783  NULL,                            /* unmount */
     784  NULL,                            /* fsunmount */
     785  NULL,                            /* utime, */
     786  NULL,                            /* evaluate_link */
     787  NULL,                            /* symlink */
     788  NULL,                            /* readlin */
     789};
     790
     791rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
     792  rtems_tftp_open,
     793  rtems_tftp_close,
     794  rtems_tftp_read,
     795  rtems_tftp_write,
     796  NULL,
     797  NULL,
     798  NULL,
     799  NULL,
     800  NULL,
     801  NULL,
     802  NULL,
     803  NULL,
     804};
Note: See TracChangeset for help on using the changeset viewer.