|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.