Annotation of Net2/arch/i386/netboot/tftp.c, revision 1.1.1.1

1.1       root        1: /* netboot
                      2:  *
                      3:  * tftp.c,v
                      4:  * Revision 1.1  1993/07/08  16:04:12  brezak
                      5:  * Diskless boot prom code from Jim McKim ([email protected])
                      6:  *
                      7:  * Revision 1.3  1993/06/30  20:14:16  mckim
                      8:  * Added BOOTP support.
                      9:  *
                     10:  * Revision 1.2  1993/05/28  20:01:31  mckim
                     11:  * Fixed various StartProg() problems.
                     12:  *
                     13:  * Revision 1.1.1.1  1993/05/28  11:41:07  mckim
                     14:  * Initial version.
                     15:  *
                     16:  *
                     17:  * source in this file came from
                     18:  * the Mach ethernet boot written by Leendert van Doorn.
                     19:  *
                     20:  * Trivial File Transfer Protocol (see RFC 783).
                     21:  *
                     22:  * Copyright (c) 1992 by Leendert van Doorn
                     23:  */
                     24: #include "proto.h"
                     25: #include "assert.h"
                     26: #include "param.h"
                     27: #include "packet.h"
                     28: #include "ether.h"
                     29: #include "inet.h"
                     30: #include "tftp.h"
                     31: #include "arp.h"
                     32: 
                     33: ipaddr_t tftp_server;  /* IP address of TFTP server */
                     34: ipaddr_t tftp_gateway;
                     35: static char tftp_file_name[100];
                     36: static short block;            /* current block */
                     37: static int ctid, stid;         /* UDP client and server TID (network order) */
                     38: 
                     39: extern u_long work_area_org;
                     40: 
                     41: /*
                     42:  * Print IP address in a readable form
                     43:  */
                     44: void
                     45: IpPrintAddr(ipaddr_t addr) {
                     46:   inetaddr_t ip;
                     47: 
                     48:   ip.a = addr;
                     49:   printf("%d.%d.%d.%d", ip.s.a0, ip.s.a1, ip.s.a2, ip.s.a3);
                     50: }
                     51: 
                     52: /*
                     53:  * Generic TFTP error routine
                     54:  */
                     55: static void
                     56: TftpFail(ipaddr_t fromaddr, ipaddr_t toaddr, char *filename, char *reason) {
                     57:   printf("Tftp of file '%s' from ", filename);
                     58:   IpPrintAddr(fromaddr);
                     59:   printf(" failed, %s\n", reason);
                     60: }
                     61: 
                     62: /*
                     63:  * One complement check sum
                     64:  */
                     65: static u_short
                     66: InChecksum(char *cp, u_long count) {
                     67:   u_short *sp;
                     68:   u_long sum, oneword = 0x00010000;
                     69: 
                     70:   for (sum = 0, sp = (u_short *)cp, count >>= 1; count--; ) {
                     71:     sum += *sp++;
                     72:     if (sum >= oneword) {
                     73:       /* wrap carry into low bit */
                     74:       sum -= oneword;
                     75:       sum++;
                     76:     }
                     77:   }
                     78:   return ~sum;
                     79: }
                     80: 
                     81: /*
                     82:  * Setup the standard IP header fields for a destination,
                     83:  * and send packet (possibly using the gateway).
                     84:  */
                     85: void
                     86: IpSend(packet_t *pkt, ipaddr_t dst, ipaddr_t gateway) {
                     87:   iphdr_t *ip;
                     88:   u_char edst[ETH_ADDRSIZE];
                     89:   static int ipid = 0;
                     90: #if TRACE > 0
                     91: DUMP_STRUCT("IpSend: pkt (front)", pkt, 100);
                     92: #endif
                     93:   pkt->pkt_offset -= sizeof(iphdr_t);
                     94:   pkt->pkt_len += sizeof(iphdr_t);
                     95:   ip = (iphdr_t *) pkt->pkt_offset;
                     96:   ip->ip_vhl = (IP_VERSION << 4) | (sizeof(*ip) >> 2);
                     97:   ip->ip_tos = 0;
                     98:   ip->ip_len = htons(pkt->pkt_len);
                     99:   ip->ip_id = ipid++;
                    100:   ip->ip_off = 0;
                    101:   ip->ip_ttl = IP_FRAGTTL;
                    102:   ip->ip_p = IP_PROTO_UDP;
                    103:   ip->ip_src = ip_myaddr ? ip_myaddr : IP_ANYADDR;
                    104:   ip->ip_dst = dst;
                    105:   ip->ip_sum = 0;
                    106:   ip->ip_sum = InChecksum((char *)ip, sizeof(*ip));
                    107: #if 0
                    108: /* DUMP_STRUCT("pkt (after)", pkt, 100); */
                    109: DUMP_STRUCT("ip", ip, sizeof(iphdr_t)+pkt->pkt_len);
                    110: #endif
                    111:   if (ArpResolve(pkt, gateway ? gateway : dst, edst)) {
                    112:     EtherSend(pkt, ETHTYPE_IP, edst);
                    113:     PktRelease(pkt);
                    114:   }
                    115: }
                    116: 
                    117: /*
                    118:  * States which TFTP can be in
                    119:  */
                    120: enum TftpPacketStatus {
                    121:   TFTP_RECD_GOOD_PACKET,
                    122:   TFTP_RECD_BAD_PACKET,
                    123:   TFTP_RECD_SERVER_ABORT,
                    124: };
                    125: 
                    126: /*
                    127:  * Pseudo header to compute UDP checksum
                    128:  */
                    129: struct pseudoheader {
                    130:   ipaddr_t     ph_src;
                    131:   ipaddr_t     ph_dst;
                    132:   u_char       ph_zero;
                    133:   u_char       ph_prot;
                    134:   u_short      ph_length;
                    135: };
                    136: 
                    137: /*
                    138:  * Determine whether this IP packet is the TFTP data packet
                    139:  * we were expecting. When a broadcast TFTP request was made
                    140:  * we'll set the TFTP server address as well.
                    141:  */
                    142: static enum TftpPacketStatus
                    143: TftpDigestPacket(packet_t *pkt, char *rbuf, u_long *rlen) {
                    144:   iphdr_t *ip;
                    145:   udphdr_t *up;
                    146:   tftphdr_t *tp;
                    147:   struct pseudoheader ph;
                    148:   u_short oldsum, sum;
                    149:   u_short udplength;
                    150: 
                    151:   /* check for minimum size tftp packet */
                    152:   if (pkt->pkt_len < (sizeof(ethhdr_t) + sizeof(iphdr_t) +
                    153:                      sizeof(udphdr_t) + sizeof(tftphdr_t))) {
                    154: #if 0
                    155:     printe("TftpDigestPacket: bad packet size %d\n", pkt->pkt_len);
                    156: #endif
                    157:     return TFTP_RECD_BAD_PACKET;
                    158:   }
                    159: 
                    160:   /* IP related checks */
                    161:   ip = (iphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t));
                    162:   if (tftp_server != IP_BCASTADDR && ip->ip_src != tftp_server) {
                    163: #if 0
                    164:     printe("TftpDigestPacket: incorrect ip source address 0x%x\n", ip->ip_src);
                    165: #endif
                    166:     return TFTP_RECD_BAD_PACKET;
                    167:   }
                    168:   if (ntohs(ip->ip_len) <
                    169:       sizeof(iphdr_t) + sizeof(udphdr_t) + sizeof(tftphdr_t)) {
                    170: #if 0
                    171:     printe("TftpDigestPacket: bad ip length %d\n", ip->ip_len);
                    172: #endif
                    173:     return TFTP_RECD_BAD_PACKET;
                    174:   }
                    175:   if (ip->ip_p != IP_PROTO_UDP) {
                    176: #if 0
                    177:     printe("TftpDigestPacket: wrong ip protocol type 0x%x\n", ip->ip_p);
                    178: #endif
                    179:     return TFTP_RECD_BAD_PACKET;
                    180:   }
                    181:   if (ip_myaddr && ip->ip_dst != ip_myaddr) {
                    182: #if 0
                    183:     printe("TftpDigestPacket: incorrect ip destination address %x\n", ip->ip_dst);
                    184: #endif
                    185:     return TFTP_RECD_BAD_PACKET;
                    186:   }
                    187: 
                    188:   /* UDP related checks */
                    189:   up = (udphdr_t *) ((char *)ip + sizeof(iphdr_t));
                    190:   if (block && up->uh_sport != stid) {
                    191: #if 0
                    192:     printe("TftpDigestPacket: wrong udp source port 0x%x\n", up->uh_sport);
                    193: #endif
                    194:     return TFTP_RECD_BAD_PACKET;
                    195:   }
                    196:   *rlen = ntohs(up->uh_len) - sizeof(udphdr_t) - sizeof(tftphdr_t);
                    197:   if (up->uh_dport != ctid) {
                    198: #if 0
                    199:     printe("TftpDigestPacket: wrong udp destination port 0x%x\n", up->uh_dport);
                    200: #endif
                    201:     return TFTP_RECD_BAD_PACKET;
                    202:   }
                    203: 
                    204:   /* compute UDP checksum if any */
                    205:   oldsum = up->uh_sum;
                    206:   if (oldsum) {
                    207:     udplength = ntohs(up->uh_len);
                    208:     /*
                    209:      * zero the byte past the last data byte because the
                    210:      * checksum will be over an even number of bytes.
                    211:      */
                    212:     if (udplength & 01)        
                    213:       ((char *)up)[udplength] = '\0';
                    214:        
                    215:     /* set up the pseudo-header */
                    216:     ph.ph_src = ip->ip_src;
                    217:     ph.ph_dst = ip->ip_dst;
                    218:     ph.ph_zero = 0;
                    219:     ph.ph_prot = ip->ip_p;
                    220:     ph.ph_length = htons(udplength);
                    221: 
                    222:     up->uh_sum = ~InChecksum((char *)&ph, sizeof(ph));
                    223:     sum = InChecksum((char *)up, (u_long)((udplength + 1) & ~1));
                    224:     up->uh_sum = oldsum; /* put original back */
                    225:     if (oldsum == (u_short) -1)
                    226:       oldsum = 0;
                    227:     if (sum != oldsum) {
                    228: #if 0
                    229:       printe("TftpDigestPacket: Bad checksum %x != %x, length %d from ",
                    230:             sum, oldsum, udplength);
                    231:       IpPrintAddr(ip->ip_src);
                    232:       printe("\n");
                    233: #endif
                    234:       return TFTP_RECD_BAD_PACKET;
                    235:     }
                    236:   }
                    237: 
                    238:   /* TFTP related checks */
                    239:   tp = (tftphdr_t *) ((char *)up + sizeof(udphdr_t));
                    240:   switch (ntohs(tp->th_op)) {
                    241:   case TFTP_ERROR:
                    242:     printf("Diagnostic from server: error #%d, %s\n",
                    243:           ntohs(tp->th_code), &tp->th_msg);
                    244:     return TFTP_RECD_SERVER_ABORT;
                    245:   case TFTP_DATA:
                    246:     break;
                    247:   default:
                    248: #if 0
                    249:     printe("TftpDigestPacket: incorrect tftp packet type 0x%x\n", tp->th_op);
                    250: #endif
                    251:     return TFTP_RECD_BAD_PACKET;
                    252:   }
                    253: 
                    254:   /* reject old packets */
                    255:   if (ntohs(tp->th_block) != block + 1) {
                    256: #if 0
                    257:     printe("TftpDigestPacket: bad block no. %d\n", tp->th_block);
                    258: #endif
                    259:     return TFTP_RECD_BAD_PACKET;
                    260:   }
                    261: 
                    262:   /* some TFTP related check */
                    263:   if (block == 0) {
                    264:     stid = up->uh_sport;
                    265:     /* in case of a broadcast, remember server address */
                    266:     if (tftp_server == IP_BCASTADDR) {
                    267:       tftp_server = ip->ip_src;
                    268: #if 0
                    269:       printe("Found TFTP server at ");
                    270:       IpPrintAddr(tftp_server);
                    271:       printe("\n");
                    272: #endif
                    273:     }
                    274:   }
                    275:   if (stid != up->uh_sport) {
                    276: #if 0
                    277:     printe("TftpDigestPacket: incorrect udp source port 0x%x\n", up->uh_sport);
                    278: #endif
                    279:     return TFTP_RECD_BAD_PACKET;
                    280:   }
                    281: 
                    282:   bcopy(&tp->th_data, rbuf, *rlen);
                    283: 
                    284:   /* advance to next block */
                    285:   block++;
                    286:   return TFTP_RECD_GOOD_PACKET;
                    287: }
                    288: 
                    289: enum TftpStatus {
                    290:   TFTP_SUCCESS,
                    291:   TFTP_FAILURE,
                    292: };
                    293: 
                    294: static enum TftpStatus
                    295: Tftp(char *rbuf, u_long *rlen) {
                    296:   u_long time, current, timeout;
                    297:   int retry, quit;
                    298:   enum TftpStatus rc = TFTP_FAILURE;
                    299: 
                    300:   *rlen = 0;
                    301:   timeout = 4; /* four seconds */
                    302:   for (retry=0, quit=0; ++retry < NRETRIES && !quit; ) {
                    303:     /*
                    304:      * Send out a TFTP request. On the first block (actually
                    305:      * zero) we send out a read request. Every other block we
                    306:      * just acknowledge.
                    307:      */
                    308:     packet_t *pkt;
                    309:     ethhdr_t *ep;
                    310:     udphdr_t *up;
                    311:     tftphdr_t *tp;
                    312: #if TRACE > 0
                    313: printe("Tftp: block %d, try #%d\n", block, retry);
                    314: #endif
                    315:     pkt = PktAlloc(sizeof(ethhdr_t) + sizeof(iphdr_t));
                    316:     up = (udphdr_t *) pkt->pkt_offset;
                    317:     tp = (tftphdr_t *) (pkt->pkt_offset + sizeof(udphdr_t));
                    318:     if (block == 0) { /* <RRQ> | <filename> | 0 | "octet" | 0 */
                    319:       char *cp, *p;
                    320: 
                    321:       tp->th_op = htons(TFTP_RRQ);
                    322:       cp = tp->th_stuff;
                    323:       for (p = tftp_file_name; *p; )
                    324:        *cp++ = *p++;
                    325:       *cp++ = '\0';
                    326:       *cp++ = 'o';
                    327:       *cp++ = 'c';
                    328:       *cp++ = 't';
                    329:       *cp++ = 'e';
                    330:       *cp++ = 't';
                    331:       *cp++ = '\0';
                    332:       pkt->pkt_len = sizeof(udphdr_t) + (cp - (char *)tp);
                    333:     } else { /* else <ACK> | <block> */
                    334:       tp->th_op = htons(TFTP_ACK);
                    335:       tp->th_block = htons(block);
                    336: #if 0
                    337: printe("ack block %x %x\n", tp->th_block, block);
                    338: #endif
                    339:       pkt->pkt_len = sizeof(udphdr_t) + sizeof(tftphdr_t);
                    340:     }
                    341:     up->uh_sport = ctid;
                    342:     up->uh_dport = stid;
                    343:     up->uh_sum = 0;
                    344:     up->uh_len = htons(pkt->pkt_len);
                    345: #if 0
                    346: DUMP_STRUCT("tftphdr_t", tp, sizeof(tftphdr_t));
                    347: DUMP_STRUCT("udphdr_t", up, sizeof(udphdr_t));
                    348: printe("Tftp: ");
                    349: #endif
                    350:     IpSend(pkt, tftp_server, tftp_gateway);
                    351: 
                    352:     /*
                    353:      * Receive TFTP data or ARP packets
                    354:      */
                    355:     time = timer() + timeout;
                    356:     do {
                    357:       pkt = EtherReceive();
                    358:       if (pkt) {
                    359:        static int spin = 0;
                    360:        ep = (ethhdr_t *) pkt->pkt_offset;
                    361: #if 0
                    362: DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t));
                    363: #endif
                    364:        switch (ntohs(ep->eth_proto)) {
                    365:        case ETHTYPE_ARP:
                    366:          ArpInput(pkt);
                    367:          break;
                    368:        case ETHTYPE_IP:
                    369:          switch (TftpDigestPacket(pkt, rbuf, rlen)) {
                    370:          case TFTP_RECD_GOOD_PACKET:
                    371:            if (block % 8 == 0)
                    372:              printf("%c\b", "-\\|/"[spin++ % 4]);
                    373: #if 0
                    374: DUMP_STRUCT("good tftp packet", pkt, 100);
                    375: printe("TBD - copy tftp packet #%d, len %d to buffer\n", block, *rlen);
                    376: #endif
                    377:            rc = TFTP_SUCCESS;
                    378:            quit = 1;
                    379:            break;
                    380:          case TFTP_RECD_SERVER_ABORT:
                    381:            TftpFail(tftp_server, ip_myaddr, tftp_file_name, "aborted by server");
                    382: 
                    383:            rc = TFTP_FAILURE;
                    384:            quit = 1;
                    385:            break;
                    386:          default:
                    387:            /* for anything else, retry */
                    388: #if 0
                    389: printe("Tftp: bogus IP packet rec'd, still waiting\n");
                    390: #endif
                    391:            break;
                    392:          }
                    393:          break;
                    394:        default:
                    395: #if 0
                    396: printe("Tftp: undesired ethernet packet (type 0x%x) rec'd, still waiting\n",
                    397:        ep->eth_proto);
                    398: #endif
                    399:          break;
                    400:        }
                    401:        PktRelease(pkt);
                    402:       }
                    403:       current = timer();
                    404:       HandleKbdAttn();
                    405:     } while (current < time && !quit);
                    406: 
                    407: #if 0
                    408: /* TBD - move */
                    409:     eth_reset();
                    410: #endif
                    411: 
                    412:     if (current >= time)
                    413:       timeout <<= 1;
                    414:   }
                    415: 
                    416:   if (retry > NRETRIES) {
                    417:     TftpFail(tftp_server, ip_myaddr, tftp_file_name, "timed Out");
                    418:   }
                    419:   return rc;
                    420: }
                    421: 
                    422: static int tftp_at_eof = 1;
                    423: static u_long tftp_unread_bytes_in_buffer = 0;
                    424: 
                    425: void
                    426: SetTftpParms(ipaddr_t server, ipaddr_t gateway, char *file_name) {
                    427:   block = 0;
                    428:   strncpy(tftp_file_name, file_name, MAX_FILE_NAME_LEN);
                    429:   tftp_server = server;
                    430:   tftp_at_eof = 0;
                    431:   tftp_unread_bytes_in_buffer = 0;
                    432:   stid = htons(IP_PORT_TFTP);
                    433:   ctid = htons(rand());
                    434:   printf("Attempting to tftp file '%s'", tftp_file_name);
                    435:   if (tftp_server != IP_BCASTADDR) {
                    436:     printf(" from server ");
                    437:     IpPrintAddr(tftp_server);
                    438:   } else
                    439:     printf(" using IP broadcast");
                    440:   tftp_gateway = gateway;
                    441:   if (tftp_gateway) {
                    442:     printf(" using gateway ");
                    443:     IpPrintAddr(tftp_gateway);
                    444:   }
                    445:   printf("\n");
                    446: }
                    447: 
                    448: u_long
                    449: Read(void *result, u_long n_req) {
                    450:   static u_long bufp = 0;
                    451:   static char buf[PKT_DATASIZE];
                    452:   u_long length;
                    453:   u_long n_recd = 0;
                    454:   while (n_req && !tftp_at_eof) {
                    455:     if (tftp_unread_bytes_in_buffer) {
                    456:       *((char *)result)++ = buf[bufp++];
                    457:       n_req--;
                    458:       n_recd++;
                    459:       tftp_unread_bytes_in_buffer--;
                    460:     } else {
                    461:       switch (Tftp(buf, &length)) {
                    462:       case TFTP_SUCCESS:
                    463:        tftp_unread_bytes_in_buffer = length;
                    464:        bufp = 0;
                    465:        if (length < SEGSIZE)
                    466:          tftp_at_eof = 1;
                    467:        break;
                    468:       default:
                    469:        /* anything else should cause this to abend */
                    470:        tftp_unread_bytes_in_buffer = 0;
                    471:        tftp_at_eof = 1;
                    472:        break;
                    473:       }
                    474:     }
                    475:   }
                    476:   return n_recd;
                    477: }
                    478: 
                    479: u_long
                    480: PhysRead(u_long addr, u_long n_req) {
                    481:   u_long n_recd = 0;
                    482:   while (n_req) {
                    483:     char buf[512];
                    484:     u_long nd = n_req<sizeof(buf) ? n_req : sizeof(buf);
                    485:     u_long nr = Read(buf, nd);
                    486:     if (nr == 0) {
                    487:       /* problem, incomplete read */
                    488:       break;
                    489:     }
                    490:     PhysBcopy(LA(buf), addr, nr);
                    491:     n_req -= nr;
                    492:     n_recd += nr;
                    493:     addr += nr;
                    494:   }
                    495:   return n_recd;
                    496: }

unix.superglobalmegacorp.com

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