|
|
1.1 ! root 1: #include "u.h" ! 2: #include "lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "io.h" ! 7: ! 8: #include "ip.h" ! 9: ! 10: static ushort tftpport = 5000; ! 11: static int Id = 1; ! 12: static Netaddr myaddr; ! 13: static Netaddr server; ! 14: ! 15: typedef struct { ! 16: uchar header[4]; ! 17: uchar data[Segsize]; ! 18: } Tftp; ! 19: static Tftp tftpb; ! 20: ! 21: static void ! 22: hnputs(uchar *ptr, ushort val) ! 23: { ! 24: ptr[0] = val>>8; ! 25: ptr[1] = val; ! 26: } ! 27: ! 28: static void ! 29: hnputl(uchar *ptr, ulong val) ! 30: { ! 31: ptr[0] = val>>24; ! 32: ptr[1] = val>>16; ! 33: ptr[2] = val>>8; ! 34: ptr[3] = val; ! 35: } ! 36: ! 37: static ulong ! 38: nhgetl(uchar *ptr) ! 39: { ! 40: return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); ! 41: } ! 42: ! 43: static ushort ! 44: nhgets(uchar *ptr) ! 45: { ! 46: return ((ptr[0]<<8) | ptr[1]); ! 47: } ! 48: ! 49: static short endian = 1; ! 50: static char* aendian = (char*)&endian; ! 51: #define LITTLE *aendian ! 52: ! 53: static ushort ! 54: ptcl_csum(void *a, int len) ! 55: { ! 56: uchar *addr; ! 57: ulong t1, t2; ! 58: ulong losum, hisum, mdsum, x; ! 59: ! 60: addr = a; ! 61: losum = 0; ! 62: hisum = 0; ! 63: mdsum = 0; ! 64: ! 65: x = 0; ! 66: if((ulong)addr & 1) { ! 67: if(len) { ! 68: hisum += addr[0]; ! 69: len--; ! 70: addr++; ! 71: } ! 72: x = 1; ! 73: } ! 74: while(len >= 16) { ! 75: t1 = *(ushort*)(addr+0); ! 76: t2 = *(ushort*)(addr+2); mdsum += t1; ! 77: t1 = *(ushort*)(addr+4); mdsum += t2; ! 78: t2 = *(ushort*)(addr+6); mdsum += t1; ! 79: t1 = *(ushort*)(addr+8); mdsum += t2; ! 80: t2 = *(ushort*)(addr+10); mdsum += t1; ! 81: t1 = *(ushort*)(addr+12); mdsum += t2; ! 82: t2 = *(ushort*)(addr+14); mdsum += t1; ! 83: mdsum += t2; ! 84: len -= 16; ! 85: addr += 16; ! 86: } ! 87: while(len >= 2) { ! 88: mdsum += *(ushort*)addr; ! 89: len -= 2; ! 90: addr += 2; ! 91: } ! 92: if(x) { ! 93: if(len) ! 94: losum += addr[0]; ! 95: if(LITTLE) ! 96: losum += mdsum; ! 97: else ! 98: hisum += mdsum; ! 99: } else { ! 100: if(len) ! 101: hisum += addr[0]; ! 102: if(LITTLE) ! 103: hisum += mdsum; ! 104: else ! 105: losum += mdsum; ! 106: } ! 107: ! 108: losum += hisum >> 8; ! 109: losum += (hisum & 0xff) << 8; ! 110: while(hisum = losum>>16) ! 111: losum = hisum + (losum & 0xffff); ! 112: ! 113: return ~losum; ! 114: } ! 115: ! 116: static ushort ! 117: ip_csum(uchar *addr) ! 118: { ! 119: int len; ! 120: ulong sum = 0; ! 121: ! 122: len = (addr[0]&0xf)<<2; ! 123: ! 124: while(len > 0) { ! 125: sum += addr[0]<<8 | addr[1] ; ! 126: len -= 2; ! 127: addr += 2; ! 128: } ! 129: ! 130: sum = (sum & 0xffff) + (sum >> 16); ! 131: sum = (sum & 0xffff) + (sum >> 16); ! 132: return (sum^0xffff); ! 133: } ! 134: ! 135: static void ! 136: udpsend(int ctlrno, Netaddr *a, void *data, int dlen) ! 137: { ! 138: Udphdr *uh; ! 139: Etherhdr *ip; ! 140: Etherpkt pkt; ! 141: int len, ptcllen; ! 142: ! 143: ! 144: uh = (Udphdr*)&pkt; ! 145: ! 146: memset(uh, 0, sizeof(Etherpkt)); ! 147: memmove(uh->udpcksum+sizeof(uh->udpcksum), data, dlen); ! 148: ! 149: /* ! 150: * UDP portion ! 151: */ ! 152: ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); ! 153: uh->ttl = 0; ! 154: uh->udpproto = IP_UDPPROTO; ! 155: uh->frag[0] = 0; ! 156: uh->frag[1] = 0; ! 157: hnputs(uh->udpplen, ptcllen); ! 158: hnputl(uh->udpsrc, myaddr.ip); ! 159: hnputs(uh->udpsport, myaddr.port); ! 160: hnputl(uh->udpdst, a->ip); ! 161: hnputs(uh->udpdport, a->port); ! 162: hnputs(uh->udplen, ptcllen); ! 163: uh->udpcksum[0] = 0; ! 164: uh->udpcksum[1] = 0; ! 165: dlen = (dlen+1)&~1; ! 166: hnputs(uh->udpcksum, ptcl_csum(&uh->ttl, dlen+UDP_HDRSIZE)); ! 167: ! 168: /* ! 169: * IP portion ! 170: */ ! 171: ip = (Etherhdr*)&pkt; ! 172: len = sizeof(Udphdr)+dlen; ! 173: ip->vihl = IP_VER|IP_HLEN; ! 174: ip->tos = 0; ! 175: ip->ttl = 255; ! 176: hnputs(ip->length, len-ETHER_HDR); ! 177: hnputs(ip->id, Id++); ! 178: ip->frag[0] = 0; ! 179: ip->frag[1] = 0; ! 180: ip->cksum[0] = 0; ! 181: ip->cksum[1] = 0; ! 182: hnputs(ip->cksum, ip_csum(&ip->vihl)); ! 183: ! 184: /* ! 185: * Ethernet MAC portion ! 186: */ ! 187: hnputs(ip->type, ET_IP); ! 188: memmove(ip->d, a->ea, sizeof(ip->d)); ! 189: ! 190: ethertxpkt(ctlrno, &pkt, len, Timeout); ! 191: } ! 192: ! 193: static void ! 194: nak(int ctlrno, Netaddr *a, int code, char *msg, int report) ! 195: { ! 196: int n; ! 197: char buf[128]; ! 198: ! 199: buf[0] = 0; ! 200: buf[1] = Tftp_ERROR; ! 201: buf[2] = 0; ! 202: buf[3] = code; ! 203: strcpy(buf+4, msg); ! 204: n = strlen(msg) + 4 + 1; ! 205: udpsend(ctlrno, a, buf, n); ! 206: if(report) ! 207: print("\ntftp: error(%d): %s\n", code, msg); ! 208: } ! 209: ! 210: static void ! 211: dumpbytes(uchar *p, int n) ! 212: { ! 213: while(n-- > 0) ! 214: print("%2.2ux ", *p++); ! 215: print("\n"); ! 216: } ! 217: ! 218: static int ! 219: udprecv(int ctlrno, Netaddr *a, void *data, int dlen) ! 220: { ! 221: int n, len; ! 222: ushort csm; ! 223: Udphdr *h; ! 224: ulong addr; ! 225: Etherpkt pkt; ! 226: ! 227: for(;;) { ! 228: n = etherrxpkt(ctlrno, &pkt, Timeout); ! 229: if(n <= 0) ! 230: return 0; ! 231: ! 232: h = (Udphdr*)&pkt; ! 233: if(nhgets(h->type) != ET_IP) ! 234: continue; ! 235: ! 236: if(ip_csum(&h->vihl)) { ! 237: print("ip chksum error\n"); ! 238: continue; ! 239: } ! 240: if(h->vihl != (IP_VER|IP_HLEN)) { ! 241: print("ip bad vers/hlen\n"); ! 242: continue; ! 243: } ! 244: ! 245: if(h->udpproto != IP_UDPPROTO) ! 246: continue; ! 247: ! 248: h->ttl = 0; ! 249: len = nhgets(h->udplen); ! 250: hnputs(h->udpplen, len); ! 251: ! 252: if(nhgets(h->udpcksum)) { ! 253: csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE); ! 254: if(csm != 0) { ! 255: print("udp chksum error csum #%4lux len %d\n", csm, n); ! 256: dumpbytes((uchar*)&pkt, n < 64 ? n : 64); ! 257: break; ! 258: } ! 259: } ! 260: ! 261: if(a->port != 0 && nhgets(h->udpsport) != a->port) ! 262: continue; ! 263: ! 264: addr = nhgetl(h->udpsrc); ! 265: if(a->ip != Bcastip && addr != a->ip) ! 266: continue; ! 267: ! 268: len -= UDP_HDRSIZE-UDP_PHDRSIZE; ! 269: if(len > dlen) { ! 270: print("udp: packet too big\n"); ! 271: continue; ! 272: } ! 273: ! 274: memmove(data, h->udpcksum+sizeof(h->udpcksum), len); ! 275: a->ip = addr; ! 276: a->port = nhgets(h->udpsport); ! 277: memmove(a->ea, pkt.s, sizeof(a->ea)); ! 278: ! 279: return len; ! 280: } ! 281: ! 282: return 0; ! 283: } ! 284: ! 285: static int tftpblockno; ! 286: ! 287: static int ! 288: tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp) ! 289: { ! 290: int i, len, rlen; ! 291: char buf[Segsize+2]; ! 292: ! 293: buf[0] = 0; ! 294: buf[1] = Tftp_READ; ! 295: len = sprint(buf+2, "%s", name) + 2; ! 296: len += sprint(buf+len+1, "octet") + 2; ! 297: ! 298: for(i = 0; i < 5; i++){ ! 299: udpsend(ctlrno, a, buf, len); ! 300: a->port = 0; ! 301: if((rlen = udprecv(ctlrno, a, tftp, sizeof(Tftp))) < sizeof(tftp->header)) ! 302: continue; ! 303: ! 304: switch((tftp->header[0]<<8)|tftp->header[1]){ ! 305: ! 306: case Tftp_ERROR: ! 307: print("tftpopen: error (%d): %s\n", ! 308: (tftp->header[2]<<8)|tftp->header[3], tftp->data); ! 309: return -1; ! 310: ! 311: case Tftp_DATA: ! 312: tftpblockno = 1; ! 313: len = (tftp->header[2]<<8)|tftp->header[3]; ! 314: if(len != tftpblockno){ ! 315: print("tftpopen: block error: %d\n", len); ! 316: nak(ctlrno, a, 1, "block error", 0); ! 317: return -1; ! 318: } ! 319: return rlen-sizeof(tftp->header); ! 320: } ! 321: } ! 322: ! 323: print("tftpopen: failed to connect to server\n"); ! 324: return -1; ! 325: } ! 326: ! 327: static int ! 328: tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen) ! 329: { ! 330: int blockno, len; ! 331: uchar buf[4]; ! 332: ! 333: buf[0] = 0; ! 334: buf[1] = Tftp_ACK; ! 335: buf[2] = tftpblockno>>8; ! 336: buf[3] = tftpblockno; ! 337: tftpblockno++; ! 338: ! 339: dlen += sizeof(tftp->header); ! 340: ! 341: buggery: ! 342: udpsend(ctlrno, a, buf, sizeof(buf)); ! 343: ! 344: if((len = udprecv(ctlrno, a, tftp, dlen)) != dlen){ ! 345: print("tftpread: %d != %d\n", len, dlen); ! 346: nak(ctlrno, a, 2, "short read", 0); ! 347: } ! 348: ! 349: blockno = (tftp->header[2]<<8)|tftp->header[3]; ! 350: if(blockno != tftpblockno){ ! 351: print("tftpread: block error: %d, expected %d\n", blockno, tftpblockno); ! 352: ! 353: if(blockno == tftpblockno-1) ! 354: goto buggery; ! 355: nak(ctlrno, a, 1, "block error", 0); ! 356: ! 357: return -1; ! 358: } ! 359: ! 360: return len-sizeof(tftp->header); ! 361: } ! 362: ! 363: static void ! 364: tftpclose(int ctlrno, Netaddr *a, uchar code, char *msg) ! 365: { ! 366: nak(ctlrno, a, code, msg, 0); ! 367: } ! 368: ! 369: int ! 370: bootp(int ctlrno, char *file) ! 371: { ! 372: Bootp req, rep; ! 373: int i, dlen, segsize, text, data, bss, total; ! 374: uchar *ea, *addr, *p; ! 375: ulong entry; ! 376: Exec *exec; ! 377: char name[128], *filename, *sysname; ! 378: ! 379: if((ea = etheraddr(ctlrno)) == 0){ ! 380: print("invalid ctlrno %d\n", ctlrno); ! 381: return -1; ! 382: } ! 383: ! 384: filename = 0; ! 385: sysname = 0; ! 386: if(file && *file){ ! 387: strcpy(name, file); ! 388: if(filename = strchr(name, ':')){ ! 389: if(filename != name && *(filename-1) != '\\'){ ! 390: sysname = name; ! 391: *filename++ = 0; ! 392: } ! 393: } ! 394: else ! 395: filename = name; ! 396: } ! 397: ! 398: ! 399: memset(&req, 0, sizeof(req)); ! 400: req.op = Bootrequest; ! 401: req.htype = 1; /* ethernet */ ! 402: req.hlen = Eaddrlen; /* ethernet */ ! 403: memmove(req.chaddr, ea, Eaddrlen); ! 404: ! 405: myaddr.ip = 0; ! 406: myaddr.port = BPportsrc; ! 407: memmove(myaddr.ea, ea, sizeof(myaddr.ea)); ! 408: ! 409: for(i = 0; i < 10; i++) { ! 410: server.ip = Bcastip; ! 411: server.port = BPportdst; ! 412: memset(server.ea, 0xFF, sizeof(server.ea)); ! 413: udpsend(ctlrno, &server, &req, sizeof(req)); ! 414: if(udprecv(ctlrno, &server, &rep, sizeof(rep)) <= 0) ! 415: continue; ! 416: if(memcmp(req.chaddr, rep.chaddr, Eaddrlen)) ! 417: continue; ! 418: if(rep.htype != 1 || rep.hlen != Eaddrlen) ! 419: continue; ! 420: if(sysname == 0 || strcmp(sysname, rep.sname) == 0) ! 421: break; ! 422: } ! 423: if(i >= 10) { ! 424: print("bootp timed out\n"); ! 425: return -1; ! 426: } ! 427: ! 428: if(filename == 0 || *filename == 0) ! 429: filename = rep.file; ! 430: if(rep.sname[0] != '\0') ! 431: print("%s:%s\n", rep.sname, filename); ! 432: ! 433: myaddr.ip = nhgetl(rep.yiaddr); ! 434: myaddr.port = tftpport++; ! 435: server.port = TFTPport; ! 436: ! 437: if((dlen = tftpopen(ctlrno, &server, filename, &tftpb)) < 0) ! 438: return -1; ! 439: ! 440: exec = (Exec*)(tftpb.data); ! 441: if(dlen < sizeof(Exec) || GLLONG(exec->magic) != I_MAGIC){ ! 442: nak(ctlrno, &server, 0, "bad magic number", 1); ! 443: return -1; ! 444: } ! 445: text = GLLONG(exec->text); ! 446: data = GLLONG(exec->data); ! 447: bss = GLLONG(exec->bss); ! 448: total = text+data+bss; ! 449: entry = GLLONG(exec->entry); ! 450: print("%d", text); ! 451: ! 452: addr = (uchar*)PADDR(entry); ! 453: p = tftpb.data+sizeof(Exec); ! 454: dlen -= sizeof(Exec); ! 455: segsize = text; ! 456: for(;;){ ! 457: if(dlen == 0){ ! 458: if((dlen = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data))) < 0) ! 459: return -1; ! 460: p = tftpb.data; ! 461: } ! 462: if(segsize <= dlen) ! 463: i = segsize; ! 464: else ! 465: i = dlen; ! 466: memmove(addr, p, i); ! 467: ! 468: addr += i; ! 469: p += i; ! 470: segsize -= i; ! 471: dlen -= i; ! 472: ! 473: if(segsize <= 0){ ! 474: if(data == 0) ! 475: break; ! 476: print("+%d", data); ! 477: segsize = data; ! 478: data = 0; ! 479: addr = (uchar*)PGROUND((ulong)addr); ! 480: } ! 481: } ! 482: tftpclose(ctlrno, &server, 3, "ok"); ! 483: print("+%d=%d\n", bss, total); ! 484: print("entry: 0x%lux\n", entry); ! 485: ! 486: (*(void(*)(void))(PADDR(entry)))(); ! 487: ! 488: return 0; ! 489: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.