home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / linux_bo / netboot.zoo / tftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-04  |  6.2 KB  |  288 lines

  1. #include "protocol.h"
  2. #include "bootinc.h"
  3.  
  4.  
  5. #define IPPORT_TFTP    69
  6.  
  7. #ifndef TFTP_TIMEOUT
  8. #define TFTP_TIMEOUT        5               /* secs between rexmt's */
  9. #endif
  10.  
  11. #define SEGSIZE        512               /* data segment size */
  12.  
  13. /*
  14.  * Packet types.
  15.  */
  16. #define    RRQ    01                   /* read request */
  17. #define    WRQ    02                   /* write request */
  18. #define    DATA    03                   /* data packet */
  19. #define    ACK    04                   /* acknowledgement */
  20. #define    ERROR    05                   /* error code */
  21.  
  22. struct tftphdr
  23. {
  24.     short           th_opcode;           /* packet type */
  25.     union
  26.     {
  27.         short           tu_block;       /* block # */
  28.         short           tu_code;       /* error code */
  29.         char            tu_stuff[1];       /* request packet stuff */
  30.     }               th_u;
  31.     char            th_data[1];           /* data or error string */
  32. };
  33.  
  34. #define    th_block    th_u.tu_block
  35. #define    th_code        th_u.tu_code
  36. #define    th_stuff    th_u.tu_stuff
  37. #define    th_msg        th_data
  38.  
  39. /*
  40.  * Error codes.
  41.  */
  42. #define    EUNDEF        0               /* not defined */
  43. #define    ENOTFOUND    1               /* file not found */
  44. #define    EACCESS        2               /* access violation */
  45. #define    ENOSPACE    3               /* disk full or allocation
  46.                             * exceeded */
  47. #define    EBADOP        4               /* illegal TFTP operation */
  48. #define    EBADID        5               /* unknown transfer ID */
  49. #define    EEXISTS        6               /* file already exists */
  50. #define    ENOUSER        7               /* no such user */
  51.  
  52. #define PKTSIZE    SEGSIZE+4
  53.  
  54. static          tftp_buffer[PKTSIZE];
  55.  
  56. int
  57. makerequest(int request, char *name, struct tftphdr * tp)
  58. {
  59.     register char  *cp;
  60.  
  61.     tp->th_opcode = intswap((uint16) request);
  62.     cp = tp->th_stuff;
  63.     strcpy(cp, name);
  64.     cp += strlen(name);
  65.     *cp++ = '\0';
  66.     strcpy(cp, "octet");
  67.     cp += 5;
  68.     *cp++ = '\0';
  69.     return (cp - (char *) tp);
  70. }
  71.  
  72. struct errmsg
  73. {
  74.     int             e_code;
  75.     char           *e_msg;
  76. }               errmsgs[] =
  77.  
  78. {
  79.     {    EUNDEF, "Undefined error code"     },
  80.     {    ENOTFOUND, "File not found"    },
  81.     {    EACCESS, "Access violation"    },
  82.     {    ENOSPACE, "Disk full or allocation exceeded"    },
  83.     {    EBADOP, "Illegal TFTP operation"    },
  84.     {    EBADID, "Unknown transfer ID"    },
  85.     {    EEXISTS, "File already exists"    },
  86.     {    ENOUSER, "No such user"    },
  87.     {    -1, 0    }
  88. };
  89.  
  90. void
  91. tpacket(char *s, struct tftphdr * tp, int n)
  92. {
  93.     static char    *opcodes[] =
  94.     {"#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR"};
  95.     register char  *cp,
  96.                    *file;
  97.     uint16          op;
  98.  
  99.     op = intswap(tp->th_opcode);
  100.  
  101.     if (op < RRQ || op > ERROR)
  102.         n_printf("%s opcode=%x ", s, op);
  103.     else
  104.         n_printf("%s %s ", s, opcodes[op]);
  105.  
  106.     switch (op)
  107.     {
  108.  
  109.     case RRQ:
  110.     case WRQ:
  111.         n -= 2;
  112.         file = cp = tp->th_stuff;
  113.         cp = strchr(cp, '\0');
  114.         n_printf("<file=%s, mode=%s>\n", file, cp + 1);
  115.         break;
  116.  
  117.     case DATA:
  118.         n_printf("<block=%d, %d bytes>\n", intswap(tp->th_block), n - 4);
  119.         break;
  120.  
  121.     case ACK:
  122.         n_printf("<block=%d>\n", intswap(tp->th_block));
  123.         break;
  124.  
  125.     case ERROR:
  126.         n_printf("<code=%d, msg=%s>\n", intswap(tp->th_code), tp->th_msg);
  127.         break;
  128.     }
  129. }
  130.  
  131. /*
  132.  * Receive a file.
  133.  */
  134. int
  135. tftp_get(char *name)
  136. {
  137.     struct tftphdr *ap;
  138.     struct tftphdr *dp;
  139.     int             block;
  140.     int             size;
  141.     int             firsttrip;
  142.     int             port;
  143.     unsigned long   start_time;
  144.     int             ulen;
  145.     int             y;
  146.     int             retcode;
  147.     int             j;
  148.     int             delay;
  149.     char            c;
  150.  
  151.     block = 1;
  152.     firsttrip = 1;
  153.     port = IPPORT_TFTP;
  154.     ap = (struct tftphdr *) tftp_buffer;
  155.     dp = (struct tftphdr *) udp_rxdata.data;
  156.     retcode = 0;
  157.  
  158.     while (1)
  159.     {
  160.         if (firsttrip)
  161.         {
  162.             size = makerequest(RRQ, name, ap);
  163.         }
  164.         else
  165.         {
  166.             ap->th_opcode = intswap((uint16) ACK);
  167.             ap->th_block = intswap((uint16) (block));
  168.             size = 4;
  169.             block++;
  170.         }
  171. send_ack:
  172.         if (debug)
  173.             tpacket("sending", ap, size);
  174.         y = netusend(nnipserver, nnserveraddr, port, IPPORT_TFTP, (unsigned char *) ap, size);
  175.         if (y)
  176.         {
  177.             return (y);
  178.         }
  179. get_next:
  180.         start_time = n_secs();
  181.         delay = TFTP_TIMEOUT;
  182.         while ((n_secs() - start_time) < (unsigned long) delay)
  183.         {
  184.             if (monitor_check() > 1)
  185.                 return 2000;
  186.             ulen = udprecv(&udp_rxdata, IPPORT_TFTP);
  187.             if (!ulen)
  188.                 continue;    /* process all packets */
  189.             if (ulen < 0)
  190.                 return -ulen;
  191.             delay = 0;
  192.             break;
  193.         }
  194.         if (delay)
  195.         {
  196.             retcode = 1020;
  197.             goto abort;
  198.         }
  199.         if (firsttrip)
  200.         {
  201.             firsttrip = 0;
  202.             port = intswap(udp_rxdata.u.source);
  203.         }
  204.         /* copy their port number, sice they may move it */
  205.         if (debug)
  206.             tpacket("received", dp, ulen);
  207.         /* should verify client address */
  208.         dp->th_opcode = intswap(dp->th_opcode);
  209.         dp->th_block = intswap(dp->th_block);
  210.         if (dp->th_opcode == ERROR)
  211.         {
  212.             n_printf("Tftp: %d: %s\n", dp->th_code, dp->th_msg);
  213.             retcode = 1021;
  214.             goto abort;
  215.         }
  216.         if (dp->th_opcode != DATA)
  217.         {
  218.             retcode = 1022;
  219.             break;
  220.         }
  221.         n_printf("\rBlock %d", dp->th_block);
  222.         if (dp->th_block != block)
  223.         {
  224.             n_printf("Missed something\n");
  225.             /*
  226.              * On an error, try to synchronize both sides.
  227.              */
  228.             for (j = 0;  ; j++)
  229.             {
  230.                 ulen = udprecv(&udp_rxdata, IPPORT_TFTP);
  231.                 if (ulen < 0)
  232.                     return -ulen;
  233.                 if (ulen == 0)
  234.                     break;
  235.             }
  236.             if (j && debug)
  237.             {
  238.                 n_printf("discarded %d packets\n", j);
  239.             }
  240.             if (dp->th_block == (block - 1))
  241.             {
  242.                 goto send_ack;    /* resend ack */
  243.             }
  244.             goto get_next;
  245.         }
  246.         /* otherwise good */
  247.         /* update data rxed , ulen - 4 len */
  248.         size = ulen - 4;
  249.         if (block ==  1)
  250.         {
  251.                            if (size < SEGSIZE)
  252.                            {
  253.                 c = dp->th_data[0];
  254.                 if (c == '\n' || c == '\r' ||
  255.                  (c >= ' ' &&  c < '\177'))
  256.                 {
  257.                     /* take a punt and call it ascii */
  258.                     n_printf("%s", dp->th_data);
  259.                 }
  260.                 retcode = 3000;
  261.                                break;
  262.             }
  263.             retcode = decode_header(dp->th_data);
  264.             if (retcode)
  265.                 break;
  266.         }
  267.         else
  268.         {
  269.             if (size)
  270.             {
  271.                 retcode = place_data(dp->th_data, size);
  272.                 if (retcode)
  273.                     break;
  274.             }
  275.             if (size < SEGSIZE)
  276.                 break;
  277.         }
  278.         continue;
  279.     }
  280.  
  281. abort:
  282.     /* ok to ack, since user */
  283.     ap->th_opcode = intswap((uint16) ACK);    /* has seen err msg */
  284.     ap->th_block = intswap((uint16) block);
  285.     y = netusend(nnipserver, nnserveraddr, port, IPPORT_TFTP, (unsigned char *) ap, 4);
  286.     return retcode;
  287. }
  288.