Changeset c1a37d3e in rtems
- Timestamp:
- 02/04/99 14:54:31 (25 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- 8cce445
- Parents:
- 7c7fd4d
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/exec/libnetworking/lib/tftpDriver.c
r7c7fd4d rc1a37d3e 19 19 #include <string.h> 20 20 #include <unistd.h> 21 #include <fcntl.h> 21 22 #include <rtems.h> 22 23 #include <rtems/libio.h> … … 140 141 * Number of streams open at the same time 141 142 */ 143 142 144 static rtems_id tftp_mutex; 143 145 static int nStreams; 144 146 static struct tftpStream ** volatile tftpStreams; 145 147 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; 148 typedef const char *tftp_node; 149 extern rtems_filesystem_operations_table rtems_tftp_ops; 150 extern rtems_filesystem_file_handlers_r rtems_tftp_handlers; 151 152 /* 153 * Direct copy from the IMFS. Look at this. 154 */ 155 156 rtems_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 }; 152 170 153 171 int rtems_tftp_mount_me( … … 155 173 ) 156 174 { 157 tftp_fs_info *fs_info;158 175 rtems_status_code sc; 159 176 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 */ 171 202 172 203 sc = rtems_semaphore_create ( … … 179 210 RTEMS_LOCAL, 180 211 0, 181 & fs_info->tftp_mutex212 &tftp_mutex 182 213 ); 183 214 184 215 if (sc != RTEMS_SUCCESSFUL) 185 set_errno_and_return_minus_one( ENOMEM ); /* ??? */216 set_errno_and_return_minus_one( ENOMEM ); 186 217 187 218 return 0; … … 191 222 * Initialize the TFTP driver 192 223 */ 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 225 int 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; 205 246 } 206 247 … … 339 380 ) 340 381 { 341 set_errno_and_return_minus_one( EIO ); 342 } 382 set_errno_and_return_minus_one( EIO ); 383 } 384 343 385 /* 344 386 * XXX - Fix return values. 345 387 */ 346 388 347 int TFTP_eval_path(389 int rtems_tftp_eval_path( 348 390 const char *pathname, /* IN */ 349 391 int flags, /* IN */ … … 351 393 ) 352 394 { 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; 401 411 402 412 return 0; 403 413 } 404 414 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 416 int rtems_tftp_open( 417 rtems_libio_t *iop, 418 const char *new_name, 419 unsigned32 flag, 420 unsigned32 mode 412 421 ) 413 422 { 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; 566 637 } 567 638 … … 569 640 * Read from a TFTP stream 570 641 */ 571 rtems_device_driver rtems_tftp_read( 572 rtems_device_major_number major, 573 rtems_device_minor_number minor, 574 void *pargp 642 643 int rtems_tftp_read( 644 rtems_libio_t *iop, 645 void *buffer, 646 unsigned32 count 575 647 ) 576 648 { 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; 644 720 } 645 721 … … 647 723 * Close a TFTP stream 648 724 */ 649 rtems_device_driver rtems_tftp_close( 650 rtems_device_major_number major, 651 rtems_device_minor_number minor, 652 void *pargp 725 int rtems_tftp_close( 726 rtems_libio_t *iop 653 727 ) 654 728 { 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 745 int rtems_tftp_write( 746 rtems_libio_t *iop, 747 const void *buffer, 748 unsigned32 count 676 749 ) 677 750 { 678 751 return RTEMS_NOT_CONFIGURED; 679 752 } 680 753 … … 685 758 ) 686 759 { 687 return RTEMS_NOT_CONFIGURED; 688 } 760 return RTEMS_NOT_CONFIGURED; 761 } 762 763 rtems_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 771 rtems_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 791 rtems_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 19 19 #include <string.h> 20 20 #include <unistd.h> 21 #include <fcntl.h> 21 22 #include <rtems.h> 22 23 #include <rtems/libio.h> … … 140 141 * Number of streams open at the same time 141 142 */ 143 142 144 static rtems_id tftp_mutex; 143 145 static int nStreams; 144 146 static struct tftpStream ** volatile tftpStreams; 145 147 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; 148 typedef const char *tftp_node; 149 extern rtems_filesystem_operations_table rtems_tftp_ops; 150 extern rtems_filesystem_file_handlers_r rtems_tftp_handlers; 151 152 /* 153 * Direct copy from the IMFS. Look at this. 154 */ 155 156 rtems_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 }; 152 170 153 171 int rtems_tftp_mount_me( … … 155 173 ) 156 174 { 157 tftp_fs_info *fs_info;158 175 rtems_status_code sc; 159 176 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 */ 171 202 172 203 sc = rtems_semaphore_create ( … … 179 210 RTEMS_LOCAL, 180 211 0, 181 & fs_info->tftp_mutex212 &tftp_mutex 182 213 ); 183 214 184 215 if (sc != RTEMS_SUCCESSFUL) 185 set_errno_and_return_minus_one( ENOMEM ); /* ??? */216 set_errno_and_return_minus_one( ENOMEM ); 186 217 187 218 return 0; … … 191 222 * Initialize the TFTP driver 192 223 */ 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 225 int 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; 205 246 } 206 247 … … 339 380 ) 340 381 { 341 set_errno_and_return_minus_one( EIO ); 342 } 382 set_errno_and_return_minus_one( EIO ); 383 } 384 343 385 /* 344 386 * XXX - Fix return values. 345 387 */ 346 388 347 int TFTP_eval_path(389 int rtems_tftp_eval_path( 348 390 const char *pathname, /* IN */ 349 391 int flags, /* IN */ … … 351 393 ) 352 394 { 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; 401 411 402 412 return 0; 403 413 } 404 414 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 416 int rtems_tftp_open( 417 rtems_libio_t *iop, 418 const char *new_name, 419 unsigned32 flag, 420 unsigned32 mode 412 421 ) 413 422 { 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; 566 637 } 567 638 … … 569 640 * Read from a TFTP stream 570 641 */ 571 rtems_device_driver rtems_tftp_read( 572 rtems_device_major_number major, 573 rtems_device_minor_number minor, 574 void *pargp 642 643 int rtems_tftp_read( 644 rtems_libio_t *iop, 645 void *buffer, 646 unsigned32 count 575 647 ) 576 648 { 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; 644 720 } 645 721 … … 647 723 * Close a TFTP stream 648 724 */ 649 rtems_device_driver rtems_tftp_close( 650 rtems_device_major_number major, 651 rtems_device_minor_number minor, 652 void *pargp 725 int rtems_tftp_close( 726 rtems_libio_t *iop 653 727 ) 654 728 { 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 745 int rtems_tftp_write( 746 rtems_libio_t *iop, 747 const void *buffer, 748 unsigned32 count 676 749 ) 677 750 { 678 751 return RTEMS_NOT_CONFIGURED; 679 752 } 680 753 … … 685 758 ) 686 759 { 687 return RTEMS_NOT_CONFIGURED; 688 } 760 return RTEMS_NOT_CONFIGURED; 761 } 762 763 rtems_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 771 rtems_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 791 rtems_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 19 19 #include <string.h> 20 20 #include <unistd.h> 21 #include <fcntl.h> 21 22 #include <rtems.h> 22 23 #include <rtems/libio.h> … … 140 141 * Number of streams open at the same time 141 142 */ 143 142 144 static rtems_id tftp_mutex; 143 145 static int nStreams; 144 146 static struct tftpStream ** volatile tftpStreams; 145 147 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; 148 typedef const char *tftp_node; 149 extern rtems_filesystem_operations_table rtems_tftp_ops; 150 extern rtems_filesystem_file_handlers_r rtems_tftp_handlers; 151 152 /* 153 * Direct copy from the IMFS. Look at this. 154 */ 155 156 rtems_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 }; 152 170 153 171 int rtems_tftp_mount_me( … … 155 173 ) 156 174 { 157 tftp_fs_info *fs_info;158 175 rtems_status_code sc; 159 176 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 */ 171 202 172 203 sc = rtems_semaphore_create ( … … 179 210 RTEMS_LOCAL, 180 211 0, 181 & fs_info->tftp_mutex212 &tftp_mutex 182 213 ); 183 214 184 215 if (sc != RTEMS_SUCCESSFUL) 185 set_errno_and_return_minus_one( ENOMEM ); /* ??? */216 set_errno_and_return_minus_one( ENOMEM ); 186 217 187 218 return 0; … … 191 222 * Initialize the TFTP driver 192 223 */ 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 225 int 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; 205 246 } 206 247 … … 339 380 ) 340 381 { 341 set_errno_and_return_minus_one( EIO ); 342 } 382 set_errno_and_return_minus_one( EIO ); 383 } 384 343 385 /* 344 386 * XXX - Fix return values. 345 387 */ 346 388 347 int TFTP_eval_path(389 int rtems_tftp_eval_path( 348 390 const char *pathname, /* IN */ 349 391 int flags, /* IN */ … … 351 393 ) 352 394 { 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; 401 411 402 412 return 0; 403 413 } 404 414 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 416 int rtems_tftp_open( 417 rtems_libio_t *iop, 418 const char *new_name, 419 unsigned32 flag, 420 unsigned32 mode 412 421 ) 413 422 { 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; 566 637 } 567 638 … … 569 640 * Read from a TFTP stream 570 641 */ 571 rtems_device_driver rtems_tftp_read( 572 rtems_device_major_number major, 573 rtems_device_minor_number minor, 574 void *pargp 642 643 int rtems_tftp_read( 644 rtems_libio_t *iop, 645 void *buffer, 646 unsigned32 count 575 647 ) 576 648 { 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; 644 720 } 645 721 … … 647 723 * Close a TFTP stream 648 724 */ 649 rtems_device_driver rtems_tftp_close( 650 rtems_device_major_number major, 651 rtems_device_minor_number minor, 652 void *pargp 725 int rtems_tftp_close( 726 rtems_libio_t *iop 653 727 ) 654 728 { 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 745 int rtems_tftp_write( 746 rtems_libio_t *iop, 747 const void *buffer, 748 unsigned32 count 676 749 ) 677 750 { 678 751 return RTEMS_NOT_CONFIGURED; 679 752 } 680 753 … … 685 758 ) 686 759 { 687 return RTEMS_NOT_CONFIGURED; 688 } 760 return RTEMS_NOT_CONFIGURED; 761 } 762 763 rtems_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 771 rtems_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 791 rtems_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 19 19 #include <string.h> 20 20 #include <unistd.h> 21 #include <fcntl.h> 21 22 #include <rtems.h> 22 23 #include <rtems/libio.h> … … 140 141 * Number of streams open at the same time 141 142 */ 143 142 144 static rtems_id tftp_mutex; 143 145 static int nStreams; 144 146 static struct tftpStream ** volatile tftpStreams; 145 147 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; 148 typedef const char *tftp_node; 149 extern rtems_filesystem_operations_table rtems_tftp_ops; 150 extern rtems_filesystem_file_handlers_r rtems_tftp_handlers; 151 152 /* 153 * Direct copy from the IMFS. Look at this. 154 */ 155 156 rtems_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 }; 152 170 153 171 int rtems_tftp_mount_me( … … 155 173 ) 156 174 { 157 tftp_fs_info *fs_info;158 175 rtems_status_code sc; 159 176 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 */ 171 202 172 203 sc = rtems_semaphore_create ( … … 179 210 RTEMS_LOCAL, 180 211 0, 181 & fs_info->tftp_mutex212 &tftp_mutex 182 213 ); 183 214 184 215 if (sc != RTEMS_SUCCESSFUL) 185 set_errno_and_return_minus_one( ENOMEM ); /* ??? */216 set_errno_and_return_minus_one( ENOMEM ); 186 217 187 218 return 0; … … 191 222 * Initialize the TFTP driver 192 223 */ 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 225 int 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; 205 246 } 206 247 … … 339 380 ) 340 381 { 341 set_errno_and_return_minus_one( EIO ); 342 } 382 set_errno_and_return_minus_one( EIO ); 383 } 384 343 385 /* 344 386 * XXX - Fix return values. 345 387 */ 346 388 347 int TFTP_eval_path(389 int rtems_tftp_eval_path( 348 390 const char *pathname, /* IN */ 349 391 int flags, /* IN */ … … 351 393 ) 352 394 { 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; 401 411 402 412 return 0; 403 413 } 404 414 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 416 int rtems_tftp_open( 417 rtems_libio_t *iop, 418 const char *new_name, 419 unsigned32 flag, 420 unsigned32 mode 412 421 ) 413 422 { 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; 566 637 } 567 638 … … 569 640 * Read from a TFTP stream 570 641 */ 571 rtems_device_driver rtems_tftp_read( 572 rtems_device_major_number major, 573 rtems_device_minor_number minor, 574 void *pargp 642 643 int rtems_tftp_read( 644 rtems_libio_t *iop, 645 void *buffer, 646 unsigned32 count 575 647 ) 576 648 { 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; 644 720 } 645 721 … … 647 723 * Close a TFTP stream 648 724 */ 649 rtems_device_driver rtems_tftp_close( 650 rtems_device_major_number major, 651 rtems_device_minor_number minor, 652 void *pargp 725 int rtems_tftp_close( 726 rtems_libio_t *iop 653 727 ) 654 728 { 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 745 int rtems_tftp_write( 746 rtems_libio_t *iop, 747 const void *buffer, 748 unsigned32 count 676 749 ) 677 750 { 678 751 return RTEMS_NOT_CONFIGURED; 679 752 } 680 753 … … 685 758 ) 686 759 { 687 return RTEMS_NOT_CONFIGURED; 688 } 760 return RTEMS_NOT_CONFIGURED; 761 } 762 763 rtems_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 771 rtems_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 791 rtems_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.