9 uchar broadcast[Eaddrlen] = {
10 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
13 static ushort tftpport = 5000;
15 static Netaddr myaddr;
16 static Netaddr server;
25 etherrxpkt(int ctlrno, Etherpkt *pkt, int timo)
30 n = devread(ctlrno, (uchar*)pkt, sizeof(*pkt), 0);
39 ethertxpkt(int ctlrno, Etherpkt *pkt, int len, int timo)
42 return devwrite(ctlrno, (uchar*)pkt, len, 0);
46 hnputs(uchar *ptr, ushort val)
53 hnputl(uchar *ptr, ulong val)
64 return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
70 return ((ptr[0]<<8) | ptr[1]);
73 static short endian = 1;
74 static char* aendian = (char*)&endian;
75 #define LITTLE *aendian
78 ptcl_csum(void *a, int len)
82 ulong losum, hisum, mdsum, x;
99 t1 = *(ushort*)(addr+0);
100 t2 = *(ushort*)(addr+2); mdsum += t1;
101 t1 = *(ushort*)(addr+4); mdsum += t2;
102 t2 = *(ushort*)(addr+6); mdsum += t1;
103 t1 = *(ushort*)(addr+8); mdsum += t2;
104 t2 = *(ushort*)(addr+10); mdsum += t1;
105 t1 = *(ushort*)(addr+12); mdsum += t2;
106 t2 = *(ushort*)(addr+14); mdsum += t1;
112 mdsum += *(ushort*)addr;
133 losum += (hisum & 0xff) << 8;
134 while(hisum = losum>>16)
135 losum = hisum + (losum & 0xffff);
146 len = (addr[0]&0xf)<<2;
149 sum += addr[0]<<8 | addr[1] ;
154 sum = (sum & 0xffff) + (sum >> 16);
155 sum = (sum & 0xffff) + (sum >> 16);
160 udpsend(int ctlrno, Netaddr *a, void *data, int dlen)
170 memset(uh, 0, sizeof(Etherpkt));
171 memmove(uh->udpcksum+sizeof(uh->udpcksum), data, dlen);
176 ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE);
178 uh->udpproto = IP_UDPPROTO;
181 hnputs(uh->udpplen, ptcllen);
182 hnputl(uh->udpsrc, myaddr.ip);
183 hnputs(uh->udpsport, myaddr.port);
184 hnputl(uh->udpdst, a->ip);
185 hnputs(uh->udpdport, a->port);
186 hnputs(uh->udplen, ptcllen);
190 hnputs(uh->udpcksum, ptcl_csum(&uh->ttl, dlen+UDP_HDRSIZE));
195 ip = (Etherhdr*)&pkt;
196 len = UDP_EHSIZE+UDP_HDRSIZE+dlen; /* non-descriptive names */
197 ip->vihl = IP_VER|IP_HLEN;
200 hnputs(ip->length, len-ETHER_HDR);
201 hnputs(ip->id, Id++);
206 hnputs(ip->cksum, ip_csum(&ip->vihl));
209 * Ethernet MAC portion
211 hnputs(ip->type, ET_IP);
212 memmove(ip->d, a->ea, sizeof(ip->d));
214 ethertxpkt(ctlrno, &pkt, len, Timeout);
218 nak(int ctlrno, Netaddr *a, int code, char *msg, int report)
228 n = strlen(msg) + 4 + 1;
229 udpsend(ctlrno, a, buf, n);
231 print("\ntftp: error(%d): %s\n", code, msg);
235 udprecv(int ctlrno, Netaddr *a, void *data, int dlen)
249 while(timo > msec()){
250 n = etherrxpkt(ctlrno, &pkt, timo-msec());
255 if(nhgets(h->type) != ET_IP)
258 if(ip_csum(&h->vihl)) {
259 print("ip chksum error\n");
262 if(h->vihl != (IP_VER|IP_HLEN)) {
263 print("ip bad vers/hlen\n");
267 if(h->udpproto != IP_UDPPROTO)
271 len = nhgets(h->udplen);
272 hnputs(h->udpplen, len);
274 if(nhgets(h->udpcksum)) {
275 csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE);
277 print("udp chksum error csum #%4lux len %d\n", csm, n);
282 if(a->port != 0 && nhgets(h->udpsport) != a->port)
284 if(myaddr.port != 0 && nhgets(h->udpdport) != myaddr.port)
287 addr = nhgetl(h->udpsrc);
288 if(a->ip != Bcastip && addr != a->ip)
291 len -= UDP_HDRSIZE-UDP_PHDRSIZE;
293 print("udp: packet too big\n");
297 memmove(data, h->udpcksum+sizeof(h->udpcksum), len);
299 a->port = nhgets(h->udpsport);
300 memmove(a->ea, pkt.s, sizeof(a->ea));
309 static int tftpblockno;
312 tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp)
319 len = sprint(buf+2, "%s", name) + 2;
320 len += sprint(buf+len+1, "octet") + 2;
322 for(i = 0; i < 5; i++){
323 udpsend(ctlrno, a, buf, len);
325 if((rlen = udprecv(ctlrno, a, tftp, sizeof(Tftp))) < sizeof(tftp->header))
328 switch((tftp->header[0]<<8)|tftp->header[1]){
331 print("tftpopen: error (%d): %s\n",
332 (tftp->header[2]<<8)|tftp->header[3], tftp->data);
337 len = (tftp->header[2]<<8)|tftp->header[3];
338 if(len != tftpblockno){
339 print("tftpopen: block error: %d\n", len);
340 nak(ctlrno, a, 1, "block error", 0);
343 return rlen-sizeof(tftp->header);
347 print("tftpopen: failed to connect to server\n");
352 tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen)
359 buf[2] = tftpblockno>>8;
360 buf[3] = tftpblockno;
363 dlen += sizeof(tftp->header);
366 udpsend(ctlrno, a, buf, sizeof(buf));
368 if((len = udprecv(ctlrno, a, tftp, dlen)) != dlen){
369 print("tftpread: %d != %d\n", len, dlen);
370 nak(ctlrno, a, 2, "short read", 0);
373 blockno = (tftp->header[2]<<8)|tftp->header[3];
374 if(blockno != tftpblockno){
375 print("tftpread: block error: %d, expected %d\n", blockno, tftpblockno);
377 if(blockno == tftpblockno-1)
379 nak(ctlrno, a, 1, "block error", 0);
384 return len-sizeof(tftp->header);
387 // #define BOOT_MAGIC L_MAGIC
388 #define BOOT_MAGIC 0x0700e0c3
391 getether(char *dev, uchar *ea)
397 for (i = 0; i < 8; i++) {
400 panic("no ether addr");
403 for (i = 0; i < 6; i++) {
404 ea[i] = strtoul(p, &p, 16);
405 if (*p != (i == 5 ? ' ' : '-'))
406 panic("bad ether addr");
411 static char inibuf[BOOTARGSLEN];
417 int i, fd, dlen, segsize, text, data, bss, total;
418 uchar *addr, *p, ea[6];
422 char *filename, confname[32];
427 panic("bootp devopen");
429 memset(&req, 0, sizeof(req));
430 req.op = Bootrequest;
431 req.htype = 1; /* ethernet */
432 req.hlen = Eaddrlen; /* ethernet */
433 memmove(req.chaddr, ea, Eaddrlen);
436 myaddr.port = BPportsrc;
437 memmove(myaddr.ea, ea, Eaddrlen);
439 for(i = 0; i < 10; i++) {
441 server.port = BPportdst;
442 memmove(server.ea, broadcast, sizeof(server.ea));
443 udpsend(fd, &server, &req, sizeof(req));
444 if(udprecv(fd, &server, &rep, sizeof(rep)) <= 0)
446 if(memcmp(req.chaddr, rep.chaddr, Eaddrlen))
448 if(rep.htype != 1 || rep.hlen != Eaddrlen)
453 print("bootp timed out\n");
457 sprint(confname, "/alpha/conf/%d.%d.%d.%d",
463 if(rep.sname[0] != '\0')
464 print("%s ", rep.sname);
465 print("(%d.%d.%d.%d!%d): %s...",
473 myaddr.ip = nhgetl(rep.yiaddr);
474 myaddr.port = tftpport++;
475 server.ip = nhgetl(rep.siaddr);
476 server.port = TFTPport;
478 if((dlen = tftpopen(fd, &server, confname, &tftpb)) < 0)
482 if(cp-inibuf+dlen > BOOTARGSLEN)
483 panic("conf too large");
484 memmove(cp, tftpb.data, dlen);
488 if((dlen = tftpread(fd, &server, &tftpb, sizeof(tftpb.data))) < 0)
494 filename = "/alpha/9apc";
495 cp = getconf("bootfile");
499 print("%s\n", filename);
500 myaddr.port = tftpport++;
501 server.port = TFTPport;
502 if((dlen = tftpopen(fd, &server, filename, &tftpb)) < 0)
505 exec = (Exec*)(tftpb.data);
506 if(dlen < sizeof(Exec) || GLLONG(exec->magic) != BOOT_MAGIC){
507 nak(fd, &server, 0, "bad magic number", 1);
510 text = GLLONG(exec->text);
511 data = GLLONG(exec->data);
512 bss = GLLONG(exec->bss);
513 total = text+data+bss;
514 entry = GLLONG(exec->entry);
515 if (!validrgn(entry, entry+total))
516 panic("memory range not available: %lux-%lux\n", entry, entry+total);
519 addr = (uchar*)entry;
520 p = tftpb.data+sizeof(Exec);
521 dlen -= sizeof(Exec);
525 if((dlen = tftpread(fd, &server, &tftpb, sizeof(tftpb.data))) < 0)
546 // addr = (uchar*)pground((uvlong)addr);
549 nak(fd, &server, 3, "ok", 0); /* tftpclose */
550 print("+%d=%d\n", bss, total);
551 print("entry: 0x%lux\n", entry);