Annotation of Net2/arch/i386/netboot/tftp.c, revision 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.