137da2899SCharles.Forsythimplement Mangaload; 237da2899SCharles.Forsyth 337da2899SCharles.Forsyth# to do: 437da2899SCharles.Forsyth# - set arp entry based on /lib/ndb if necessary 537da2899SCharles.Forsyth 637da2899SCharles.Forsythinclude "sys.m"; 737da2899SCharles.Forsyth sys: Sys; 837da2899SCharles.Forsyth 937da2899SCharles.Forsythinclude "draw.m"; 1037da2899SCharles.Forsyth 1137da2899SCharles.Forsythinclude "ip.m"; 1237da2899SCharles.Forsyth ip: IP; 1337da2899SCharles.Forsyth IPaddr: import ip; 1437da2899SCharles.Forsyth 1537da2899SCharles.Forsythinclude "timers.m"; 1637da2899SCharles.Forsyth timers: Timers; 1737da2899SCharles.Forsyth Timer: import timers; 1837da2899SCharles.Forsyth 19*92744810Sforsythinclude "dial.m"; 20*92744810Sforsyth dial: Dial; 21*92744810Sforsyth 2237da2899SCharles.Forsythinclude "arg.m"; 2337da2899SCharles.Forsyth 2437da2899SCharles.ForsythMangaload: module 2537da2899SCharles.Forsyth{ 2637da2899SCharles.Forsyth init: fn(nil: ref Draw->Context, nil: list of string); 2737da2899SCharles.Forsyth}; 2837da2899SCharles.Forsyth 2937da2899SCharles.Forsyth# manga parameters 3037da2899SCharles.ForsythFlashBlocksize: con 16r10000; 3137da2899SCharles.ForsythFlashSize: con 16r400000; # 4meg for now 3237da2899SCharles.ForsythFlashUserArea: con 16r3C0000; 3337da2899SCharles.Forsyth 3437da2899SCharles.Forsyth# magic values 3537da2899SCharles.ForsythFooterOffset: con 16rFFEC; 3637da2899SCharles.ForsythFooterSig: con 16rA0FFFF9F; # ARM flash library 3737da2899SCharles.ForsythFileInfosize: con 64; 3837da2899SCharles.ForsythFileNamesize: con FileInfosize - 3*4; # x, y, z 3937da2899SCharles.ForsythPacketdatasize: con 1500-28; # ether data less IP + ICMP header 4037da2899SCharles.ForsythRequestTimeout: con 500; 4137da2899SCharles.ForsythProbecount: con 10; # query unit every so many packets 4237da2899SCharles.Forsyth 4337da2899SCharles.Forsyth# manga uses extended TFTP ops in ICMP InfoRequest packets 4437da2899SCharles.ForsythTftp_Req: con 0; 4537da2899SCharles.ForsythTftp_Read: con 1; 4637da2899SCharles.ForsythTftp_Write: con 2; 4737da2899SCharles.ForsythTftp_Data: con 3; 4837da2899SCharles.ForsythTftp_Ack: con 4; 4937da2899SCharles.ForsythTftp_Error: con 5; 5037da2899SCharles.ForsythTftp_Last: con 6; 5137da2899SCharles.Forsyth 5237da2899SCharles.ForsythIcmp: adt 5337da2899SCharles.Forsyth{ 5437da2899SCharles.Forsyth ttl: int; # time to live 5537da2899SCharles.Forsyth src: IPaddr; 5637da2899SCharles.Forsyth dst: IPaddr; 5737da2899SCharles.Forsyth ptype: int; 5837da2899SCharles.Forsyth code: int; 5937da2899SCharles.Forsyth id: int; 6037da2899SCharles.Forsyth seq: int; 6137da2899SCharles.Forsyth data: array of byte; 6237da2899SCharles.Forsyth munged: int; # packet received but corrupt 6337da2899SCharles.Forsyth 6437da2899SCharles.Forsyth unpack: fn(b: array of byte): ref Icmp; 6537da2899SCharles.Forsyth}; 6637da2899SCharles.Forsyth 6737da2899SCharles.Forsyth# ICMP packet types 6837da2899SCharles.ForsythEchoReply: con 0; 6937da2899SCharles.ForsythUnreachable: con 3; 7037da2899SCharles.ForsythSrcQuench: con 4; 7137da2899SCharles.ForsythEchoRequest: con 8; 7237da2899SCharles.ForsythTimeExceed: con 11; 7337da2899SCharles.ForsythTimestamp: con 13; 7437da2899SCharles.ForsythTimestampReply: con 14; 7537da2899SCharles.ForsythInfoRequest: con 15; 7637da2899SCharles.ForsythInfoReply: con 16; 7737da2899SCharles.Forsyth 7837da2899SCharles.ForsythNmsg: con 32; 7937da2899SCharles.ForsythInterval: con 1000; # ms 8037da2899SCharles.Forsyth 8137da2899SCharles.Forsythdebug := 0; 8237da2899SCharles.Forsythflashblock := 1; # never 0, that's the boot firmware 8337da2899SCharles.Forsythmaxfilesize := 8*FlashBlocksize; 8437da2899SCharles.Forsythflashlim := FlashSize/FlashBlocksize; 8537da2899SCharles.Forsythloadinitrd := 0; 8637da2899SCharles.Forsythmaxlen := 512*1024; 8737da2899SCharles.Forsythmypid := 0; 8837da2899SCharles.ForsythDatablocksize: con 4096; 8937da2899SCharles.Forsyth 9037da2899SCharles.Forsythinit(nil: ref Draw->Context, args: list of string) 9137da2899SCharles.Forsyth{ 9237da2899SCharles.Forsyth sys = load Sys Sys->PATH; 9337da2899SCharles.Forsyth timers = load Timers Timers->PATH; 94*92744810Sforsyth dial = load Dial Dial->PATH; 9537da2899SCharles.Forsyth ip = load IP IP->PATH; 9637da2899SCharles.Forsyth ip->init(); 9737da2899SCharles.Forsyth 9837da2899SCharles.Forsyth 9937da2899SCharles.Forsyth arg := load Arg Arg->PATH; 10037da2899SCharles.Forsyth arg->init(args); 10137da2899SCharles.Forsyth arg->setusage("mangaload [-48dr] destination file"); 10237da2899SCharles.Forsyth while((o := arg->opt()) != 0) 10337da2899SCharles.Forsyth case o { 10437da2899SCharles.Forsyth '4' => 10537da2899SCharles.Forsyth flashlim = 4*1024*1024/FlashBlocksize; 10637da2899SCharles.Forsyth '8' => 10737da2899SCharles.Forsyth flashlim = 8*1024*1024/FlashBlocksize; 10837da2899SCharles.Forsyth 'r' => 10937da2899SCharles.Forsyth loadinitrd = 1; 11037da2899SCharles.Forsyth flashblock = 9; 11137da2899SCharles.Forsyth if(flashlim > 4*1024*1024/FlashBlocksize) 11237da2899SCharles.Forsyth maxfilesize = 113*FlashBlocksize; 11337da2899SCharles.Forsyth else 11437da2899SCharles.Forsyth maxfilesize = 50*FlashBlocksize; 11537da2899SCharles.Forsyth 'd' => 11637da2899SCharles.Forsyth debug++; 11737da2899SCharles.Forsyth } 11837da2899SCharles.Forsyth args = arg->argv(); 11937da2899SCharles.Forsyth if(len args != 2) 12037da2899SCharles.Forsyth arg->usage(); 12137da2899SCharles.Forsyth arg = nil; 12237da2899SCharles.Forsyth 12337da2899SCharles.Forsyth sys->pctl(Sys->NEWPGRP|Sys->FORKFD, nil); 12437da2899SCharles.Forsyth 12537da2899SCharles.Forsyth filename := hd tl args; 12637da2899SCharles.Forsyth fd := sys->open(filename, Sys->OREAD); 12737da2899SCharles.Forsyth if(fd == nil){ 12837da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: can't open %s: %r\n", filename); 12937da2899SCharles.Forsyth raise "fail:open"; 13037da2899SCharles.Forsyth } 13137da2899SCharles.Forsyth (ok, d) := sys->fstat(fd); 13237da2899SCharles.Forsyth if(ok < 0){ 13337da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: can't stat %s: %r\n", filename); 13437da2899SCharles.Forsyth raise "fail:stat"; 13537da2899SCharles.Forsyth } 13637da2899SCharles.Forsyth if(d.length > big maxfilesize){ 13737da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: file %s too long (must not exceed %d bytes)\n", 13837da2899SCharles.Forsyth filename, maxfilesize); 13937da2899SCharles.Forsyth raise "fail:size"; 14037da2899SCharles.Forsyth } 14137da2899SCharles.Forsyth filesize := int d.length; 14237da2899SCharles.Forsyth 14337da2899SCharles.Forsyth port := sys->sprint("%d", 16r8695); 144*92744810Sforsyth addr := dial->netmkaddr(hd args, "icmp", port); 145*92744810Sforsyth c := dial->dial(addr, port); 146*92744810Sforsyth if(c == nil){ 14737da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: can't dial %s: %r\n", addr); 14837da2899SCharles.Forsyth raise "fail:dial"; 14937da2899SCharles.Forsyth } 15037da2899SCharles.Forsyth 15137da2899SCharles.Forsyth tpid := timers->init(20); 15237da2899SCharles.Forsyth 15337da2899SCharles.Forsyth pids := chan of int; 15437da2899SCharles.Forsyth replies := chan [2] of ref Icmp; 15537da2899SCharles.Forsyth spawn reader(c.dfd, replies, pids); 15637da2899SCharles.Forsyth rpid := <-pids; 15737da2899SCharles.Forsyth 15837da2899SCharles.Forsyth flashoffset := flashblock * FlashBlocksize; 15937da2899SCharles.Forsyth 16037da2899SCharles.Forsyth # file name first 16137da2899SCharles.Forsyth bname := array of byte filename; 16237da2899SCharles.Forsyth l := len bname; 16337da2899SCharles.Forsyth buf := array[Packetdatasize] of byte; 16437da2899SCharles.Forsyth ip->put4(buf, 0, filesize); 16537da2899SCharles.Forsyth ip->put4(buf, 4, l); 16637da2899SCharles.Forsyth buf[8:] = bname; 16737da2899SCharles.Forsyth l += 2*4; 16837da2899SCharles.Forsyth buf[l++] = byte 0; 16937da2899SCharles.Forsyth ip->put4(buf, l, flashoffset); 17037da2899SCharles.Forsyth l += 4; 17137da2899SCharles.Forsyth { 17237da2899SCharles.Forsyth if(send(c.dfd, buf[0:l], Tftp_Write, 0) < 0) 17337da2899SCharles.Forsyth senderr(); 17437da2899SCharles.Forsyth (op, iseq, data) := recv(replies, 400); 17537da2899SCharles.Forsyth sys->print("initial reply: %d %d\n", op, iseq); 17637da2899SCharles.Forsyth if(op != Tftp_Ack){ 17737da2899SCharles.Forsyth why := "no response"; 17837da2899SCharles.Forsyth if(op == Tftp_Error) 17937da2899SCharles.Forsyth why = "manga cannot receive file"; 18037da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: %s\n", why); 18137da2899SCharles.Forsyth raise "fail:error"; 18237da2899SCharles.Forsyth } 18337da2899SCharles.Forsyth sys->print("sending %s size %d at address %d (0x%x)\n", filename, filesize, flashoffset, flashoffset); 18437da2899SCharles.Forsyth seq := 1; 18537da2899SCharles.Forsyth nsent := 0; 18637da2899SCharles.Forsyth last := 0; 18737da2899SCharles.Forsyth while((n := sys->read(fd, buf, len buf)) >= 0 && !last){ 18837da2899SCharles.Forsyth last = n != len buf; 18937da2899SCharles.Forsyth Retry: 19037da2899SCharles.Forsyth for(;;){ 19137da2899SCharles.Forsyth if(++nsent%10 == 0){ # probe 19237da2899SCharles.Forsyth o = Tftp_Req; 19337da2899SCharles.Forsyth send(c.dfd, array[0] of byte, Tftp_Req, seq); 19437da2899SCharles.Forsyth (op, iseq, data) = recv(replies, 500); 19537da2899SCharles.Forsyth if(debug || op != Tftp_Ack) 19637da2899SCharles.Forsyth sys->print("ack reply: %d %d\n", op, iseq); 19737da2899SCharles.Forsyth if(op == Tftp_Last || op == Tftp_Error){ 19837da2899SCharles.Forsyth if(op == Tftp_Last) 19937da2899SCharles.Forsyth sys->print("timed out\n"); 20037da2899SCharles.Forsyth else 20137da2899SCharles.Forsyth sys->print("error reply\n"); 20237da2899SCharles.Forsyth raise "disaster"; 20337da2899SCharles.Forsyth } 20437da2899SCharles.Forsyth if(debug) 20537da2899SCharles.Forsyth sys->print("ok\n"); 20637da2899SCharles.Forsyth continue Retry; 20737da2899SCharles.Forsyth } 20837da2899SCharles.Forsyth send(c.dfd, buf[0:n], Tftp_Data, seq); 20937da2899SCharles.Forsyth (op, iseq, data) = recv(replies, 40); 21037da2899SCharles.Forsyth case op { 21137da2899SCharles.Forsyth Tftp_Error => 21237da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: manga refused data\n"); 21337da2899SCharles.Forsyth raise "disaster"; 21437da2899SCharles.Forsyth Tftp_Ack => 21537da2899SCharles.Forsyth if(seq == iseq){ 21637da2899SCharles.Forsyth seq++; 21737da2899SCharles.Forsyth break Retry; 21837da2899SCharles.Forsyth } 21937da2899SCharles.Forsyth sys->print("sequence error: rcvd %d expected %d\n", iseq, seq); 22037da2899SCharles.Forsyth if(iseq > seq){ 22137da2899SCharles.Forsyth sys->print("unrecoverable sequence error\n"); 22237da2899SCharles.Forsyth send(c.dfd, array[0] of byte, Tftp_Data, ++seq); # stop manga 22337da2899SCharles.Forsyth raise "disaster"; 22437da2899SCharles.Forsyth } 22537da2899SCharles.Forsyth # resend 22637da2899SCharles.Forsyth sys->seek(fd, -big ((seq-iseq)*len buf), 1); 22737da2899SCharles.Forsyth seq = iseq; 22837da2899SCharles.Forsyth Tftp_Last => 22937da2899SCharles.Forsyth seq++; 23037da2899SCharles.Forsyth break Retry; # timeout ok: manga doesn't usually reply unless packet lost 23137da2899SCharles.Forsyth } 23237da2899SCharles.Forsyth } 23337da2899SCharles.Forsyth } 23437da2899SCharles.Forsyth }exception{ 23537da2899SCharles.Forsyth * => 23637da2899SCharles.Forsyth ; 23737da2899SCharles.Forsyth } 23837da2899SCharles.Forsyth kill(rpid); 23937da2899SCharles.Forsyth kill(tpid); 24037da2899SCharles.Forsyth sys->print("ok?\n"); 24137da2899SCharles.Forsyth} 24237da2899SCharles.Forsyth 24337da2899SCharles.Forsythkill(pid: int) 24437da2899SCharles.Forsyth{ 24537da2899SCharles.Forsyth if(pid) 24637da2899SCharles.Forsyth sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill"); 24737da2899SCharles.Forsyth} 24837da2899SCharles.Forsyth 24937da2899SCharles.Forsythsenderr() 25037da2899SCharles.Forsyth{ 25137da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: icmp write failed: %r\n"); 25237da2899SCharles.Forsyth raise "disaster"; 25337da2899SCharles.Forsyth} 25437da2899SCharles.Forsyth 25537da2899SCharles.Forsythsend(fd: ref Sys->FD, data: array of byte, op: int, seq: int): int 25637da2899SCharles.Forsyth{ 25737da2899SCharles.Forsyth buf := array[64*1024+512] of {* => byte 0}; 25837da2899SCharles.Forsyth buf[Odata:] = data; 25937da2899SCharles.Forsyth ip->put2(buf, Oseq, seq); 26037da2899SCharles.Forsyth buf[Otype] = byte InfoRequest; 26137da2899SCharles.Forsyth buf[Ocode] = byte op; 26237da2899SCharles.Forsyth if(sys->write(fd, buf, Odata+len data) < Odata+len data) 26337da2899SCharles.Forsyth return -1; 26437da2899SCharles.Forsyth if(debug) 26537da2899SCharles.Forsyth sys->print("sent op=%d seq=%d ld=%d\n", op, seq, len data); 26637da2899SCharles.Forsyth return 0; 26737da2899SCharles.Forsyth} 26837da2899SCharles.Forsyth 26937da2899SCharles.Forsythflush(input: chan of ref Icmp) 27037da2899SCharles.Forsyth{ 27137da2899SCharles.Forsyth for(;;)alt{ 27237da2899SCharles.Forsyth <-input => 27337da2899SCharles.Forsyth ; 27437da2899SCharles.Forsyth * => 27537da2899SCharles.Forsyth return; 27637da2899SCharles.Forsyth } 27737da2899SCharles.Forsyth} 27837da2899SCharles.Forsyth 27937da2899SCharles.Forsythrecv(input: chan of ref Icmp, msec: int): (int, int, array of byte) 28037da2899SCharles.Forsyth{ 28137da2899SCharles.Forsyth t := Timer.start(msec); 28237da2899SCharles.Forsyth alt{ 28337da2899SCharles.Forsyth <-t.timeout => 28437da2899SCharles.Forsyth return (Tftp_Last, 0, nil); 28537da2899SCharles.Forsyth ic := <-input => 28637da2899SCharles.Forsyth t.stop(); 28737da2899SCharles.Forsyth if(ic.ptype == InfoReply) 28837da2899SCharles.Forsyth return (ic.code, ic.seq, ic.data); 28937da2899SCharles.Forsyth return (Tftp_Last, 0, nil); 29037da2899SCharles.Forsyth } 29137da2899SCharles.Forsyth} 29237da2899SCharles.Forsyth 29337da2899SCharles.Forsythreader(fd: ref Sys->FD, out: chan of ref Icmp, pid: chan of int) 29437da2899SCharles.Forsyth{ 29537da2899SCharles.Forsyth pid <-= sys->pctl(0, nil); 29637da2899SCharles.Forsyth for(;;){ 29737da2899SCharles.Forsyth buf := array[64*1024+512] of byte; 29837da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 29937da2899SCharles.Forsyth if(n <= 0){ 30037da2899SCharles.Forsyth if(n == 0) 30137da2899SCharles.Forsyth sys->werrstr("unexpected eof"); 30237da2899SCharles.Forsyth break; 30337da2899SCharles.Forsyth } 30437da2899SCharles.Forsyth ic := Icmp.unpack(buf[0:n]); 30537da2899SCharles.Forsyth if(ic != nil){ 30637da2899SCharles.Forsyth if(debug) 30737da2899SCharles.Forsyth sys->print("recv type=%d op=%d seq=%d id=%d\n", ic.ptype, ic.code, ic.seq, ic.id); 30837da2899SCharles.Forsyth out <-= ic; 30937da2899SCharles.Forsyth }else 31037da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "mangaload: corrupt icmp packet rcvd\n"); 31137da2899SCharles.Forsyth } 31237da2899SCharles.Forsyth sys->print("read: %r\n"); 31337da2899SCharles.Forsyth out <-= nil; 31437da2899SCharles.Forsyth} 31537da2899SCharles.Forsyth 31637da2899SCharles.Forsyth# IP and ICMP packet header 31737da2899SCharles.ForsythOvihl: con 0; 31837da2899SCharles.ForsythOtos: con 1; 31937da2899SCharles.ForsythOlength: con 2; 32037da2899SCharles.ForsythOid: con Olength+2; 32137da2899SCharles.ForsythOfrag: con Oid+2; 32237da2899SCharles.ForsythOttl: con Ofrag+2; 32337da2899SCharles.ForsythOproto: con Ottl+1; 32437da2899SCharles.ForsythOipcksum: con Oproto+1; 32537da2899SCharles.ForsythOsrc: con Oipcksum+2; 32637da2899SCharles.ForsythOdst: con Osrc+4; 32737da2899SCharles.ForsythOtype: con Odst+4; 32837da2899SCharles.ForsythOcode: con Otype+1; 32937da2899SCharles.ForsythOcksum: con Ocode+1; 33037da2899SCharles.ForsythOicmpid: con Ocksum+2; 33137da2899SCharles.ForsythOseq: con Oicmpid+2; 33237da2899SCharles.ForsythOdata: con Oseq+2; 33337da2899SCharles.Forsyth 33437da2899SCharles.ForsythIcmp.unpack(b: array of byte): ref Icmp 33537da2899SCharles.Forsyth{ 33637da2899SCharles.Forsyth if(len b < Odata) 33737da2899SCharles.Forsyth return nil; 33837da2899SCharles.Forsyth ic := ref Icmp; 33937da2899SCharles.Forsyth ic.ttl = int b[Ottl]; 34037da2899SCharles.Forsyth ic.src = IPaddr.newv4(b[Osrc:]); 34137da2899SCharles.Forsyth ic.dst = IPaddr.newv4(b[Odst:]); 34237da2899SCharles.Forsyth ic.ptype = int b[Otype]; 34337da2899SCharles.Forsyth ic.code = int b[Ocode]; 34437da2899SCharles.Forsyth ic.seq = ip->get2(b, Oseq); 34537da2899SCharles.Forsyth ic.id = ip->get2(b, Oicmpid); 34637da2899SCharles.Forsyth ic.munged = 0; 34737da2899SCharles.Forsyth if(len b > Odata) 34837da2899SCharles.Forsyth ic.data = b[Odata:]; 34937da2899SCharles.Forsyth return ic; 35037da2899SCharles.Forsyth} 351