/************************************************************************** NFS_READ - Read File on NFS Server **************************************************************************/ static int nfs_read(int server, int port, char *fh, int offset, int len, int sport) { struct rpc_t buf, *rpc; unsigned long id; int retries; long *p; static int tokens=0; /* * Try to implement something similar to a window protocol in * terms of response to losses. On successful receive, increment * the number of tokens by 1 (cap at 256). On failure, halve it. * When the number of tokens is >= 2, use a very short timeout. */ id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_NFS); buf.u.call.vers = htonl(2); /* nfsd is version 2 */ buf.u.call.proc = htonl(NFS_READ); p = rpc_add_credentials((long *)buf.u.call.data); memcpy(p, fh, NFS_FHSIZE); p += NFS_FHSIZE / 4; *p++ = htonl(offset); *p++ = htonl(len); *p++ = 0; /* unused parameter */ for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); if (tokens >= 2) timeout = TICKS_PER_SEC/2; udp_transmit(arptable[server].ipaddr.s_addr, sport, port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, sport, &id, timeout)) { if (tokens < 256) tokens++; rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus || rpc->u.reply.data[0]) { rpc_printerror(rpc); if (rpc->u.reply.rstatus) { /* RPC failed, no verifier, data[0] */ return -9999; } if (rpc->u.reply.astatus) { /* RPC couldn't decode parameters */ return -9998; } return -ntohl(rpc->u.reply.data[0]); } else { return 0; } } else tokens >>= 1; } return -1; }
int rarp (void) { int retry; struct arprequest rarpreq; if (! eth_probe ()) return 0; network_ready = 0; grub_memset (&rarpreq, 0, sizeof (rarpreq)); rarpreq.hwtype = htons (1); rarpreq.protocol = htons (IP); rarpreq.hwlen = ETH_ALEN; rarpreq.protolen = 4; rarpreq.opcode = htons (RARP_REQUEST); grub_memmove ((char *) &rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); grub_memmove ((char *) &rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) { long timeout; eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout)) break; if (ip_abort) return 0; } if (retry < MAX_ARP_RETRIES) { network_ready = 1; return 1; } return 0; }
int rarp (void) { int retry; /* arp and rarp requests share the same packet structure. */ struct arprequest rarpreq; /* Make sure that an ethernet is probed. */ if (! eth_probe ()) return 0; /* Clear the ready flag. */ network_ready = 0; grub_memset (&rarpreq, 0, sizeof (rarpreq)); rarpreq.hwtype = htons (1); rarpreq.protocol = htons (IP); rarpreq.hwlen = ETH_ALEN; rarpreq.protolen = 4; rarpreq.opcode = htons (RARP_REQUEST); grub_memmove ((char *) &rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); /* sipaddr is already zeroed out */ grub_memmove ((char *) &rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); /* tipaddr is already zeroed out */ for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) { long timeout; eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout)) break; if (ip_abort) return 0; } if (retry < MAX_ARP_RETRIES) { network_ready = 1; return 1; } return 0; }
/************************************************************************** NFS_LOOKUP - Lookup Pathname **************************************************************************/ static int nfs_lookup(int server, int port, char *fh, char *path, char *nfh, int sport) { struct rpc_t buf, *rpc; unsigned long id; long *p; int retries; int pathlen = strlen(path); id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_NFS); buf.u.call.vers = htonl(2); /* nfsd is version 2 */ buf.u.call.proc = htonl(NFS_LOOKUP); p = rpc_add_credentials((long *)buf.u.call.data); memcpy(p, fh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(pathlen); if (pathlen & 3) { *(p + pathlen / 4) = 0; /* add zero padding */ } memcpy(p, path, pathlen); p += (pathlen + 3) / 4; for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); udp_transmit(arptable[server].ipaddr.s_addr, sport, port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, sport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus || rpc->u.reply.data[0]) { rpc_printerror(rpc); if (rpc->u.reply.rstatus) { /* RPC failed, no verifier, data[0] */ return -9999; } if (rpc->u.reply.astatus) { /* RPC couldn't decode parameters */ return -9998; } return -ntohl(rpc->u.reply.data[0]); } else { memcpy(nfh, rpc->u.reply.data + 1, NFS_FHSIZE); return 0; } } } return -1; }
/* Send the RRQ whose length is LEN. */ static int send_rrq (void) { /* Initialize some variables. */ retry = 0; block = 0; prevblock = 0; packetsize = TFTP_DEFAULTSIZE_PACKET; bcounter = 0; buf = (char *) FSYS_BUF; buf_eof = 0; buf_read = 0; saved_filepos = 0; /* Clear out the Rx queue first. It contains nothing of interest, * except possibly ARP requests from the DHCP/TFTP server. We use * polling throughout Etherboot, so some time may have passed since we * last polled the receive queue, which may now be filled with * broadcast packets. This will cause the reply to the packets we are * about to send to be lost immediately. Not very clever. */ await_reply (AWAIT_QDRAIN, 0, NULL, 0); #ifdef TFTP_DEBUG grub_printf ("send_rrq ()\n"); { int i; char *p; for (i = 0, p = (char *) &tp; i < len; i++) if (p[i] >= ' ' && p[i] <= '~') grub_putchar (p[i]); else grub_printf ("\\%x", (unsigned) p[i]); grub_putchar ('\n'); } #endif /* Send the packet. */ return udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp); }
/************************************************************************** RPC_LOOKUP - Lookup RPC Port numbers **************************************************************************/ static int rpc_lookup(int addr, int prog, int ver, int sport) { struct rpc_t buf, *rpc; unsigned long id; int retries; long *p; id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_PORTMAP); buf.u.call.vers = htonl(2); /* portmapper is version 2 */ buf.u.call.proc = htonl(PORTMAP_GETPORT); p = (long *)buf.u.call.data; *p++ = 0; *p++ = 0; /* auth credential */ *p++ = 0; *p++ = 0; /* auth verifier */ *p++ = htonl(prog); *p++ = htonl(ver); *p++ = htonl(IP_UDP); *p++ = 0; for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout; udp_transmit(arptable[addr].ipaddr.s_addr, sport, SUNRPC_PORT, (char *)p - (char *)&buf, &buf); timeout = rfc2131_sleep_interval(TIMEOUT, retries); if (await_reply(await_rpc, sport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus) { rpc_printerror(rpc); return -1; } else { return ntohl(rpc->u.reply.data[0]); } } } return -1; }
/************************************************************************** NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server **************************************************************************/ void nfs_umountall(int server) { struct rpc_t buf, *rpc; unsigned long id; int retries; long *p; if (!arptable[server].ipaddr.s_addr) { /* Haven't sent a single UDP packet to this server */ return; } if ((mount_port == -1) || (!fs_mounted)) { /* Nothing mounted, nothing to umount */ return; } id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_MOUNT); buf.u.call.vers = htonl(1); /* mountd is version 1 */ buf.u.call.proc = htonl(MOUNT_UMOUNTALL); p = rpc_add_credentials((long *)buf.u.call.data); for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); udp_transmit(arptable[server].ipaddr.s_addr, oport, mount_port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, oport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus) { rpc_printerror(rpc); } fs_mounted = 0; return; } } }
int bootp (void) { int retry; #ifndef NO_DHCP_SUPPORT int reqretry; #endif struct bootpip_t ip; unsigned long starttime; if (! eth_probe ()) return 0; network_ready = 0; #ifdef DEBUG grub_printf ("network is ready.\n"); #endif grub_memset (&ip, 0, sizeof (struct bootpip_t)); ip.bp.bp_op = BOOTP_REQUEST; ip.bp.bp_htype = 1; ip.bp.bp_hlen = ETH_ALEN; starttime = currticks (); grub_memmove (&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); ip.bp.bp_xid = xid += htonl (starttime); grub_memmove (ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); #ifdef DEBUG etherboot_printf ("bp_op = %d\n", ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif #ifdef NO_DHCP_SUPPORT grub_memmove (ip.bp.bp_vend, rfc1533_cookie, 5); #else grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); #endif for (retry = 0; retry < MAX_BOOTP_RETRIES;) { long timeout; #ifdef DEBUG grub_printf ("retry = %d\n", retry); #endif await_reply (AWAIT_QDRAIN, 0, NULL, 0); udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); timeout = rfc2131_sleep_interval (TIMEOUT, retry++); #ifdef NO_DHCP_SUPPORT if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { network_ready = 1; return 1; } #else if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { if (dhcp_reply != DHCPOFFER) { network_ready = 1; return 1; } dhcp_reply = 0; #ifdef DEBUG etherboot_printf ("bp_op = %d\n", (int) ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", (int) ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", (int) ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", (int) ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); grub_memmove (ip.bp.bp_vend + 9, (char *) &dhcp_server, sizeof (in_addr)); grub_memmove (ip.bp.bp_vend + 15, (char *) &dhcp_addr, sizeof (in_addr)); #ifdef DEBUG grub_printf ("errnum = %d\n", errnum); #endif for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES;) { int ret; #ifdef DEBUG grub_printf ("reqretry = %d\n", reqretry); #endif ret = udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); if (! ret) grub_printf ("udp_transmit failed.\n"); dhcp_reply = 0; timeout = rfc2131_sleep_interval (TIMEOUT, reqretry++); if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) if (dhcp_reply == DHCPACK) { network_ready = 1; return 1; } #ifdef DEBUG grub_printf ("dhcp_reply = %d\n", dhcp_reply); #endif if (ip_abort) return 0; } } #endif if (ip_abort) return 0; ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC); } return 0; }
static int tftp (const char *name, int (*fnc) (unsigned char *, int, int, int)) { int retry = 0; static unsigned short iport = 2000; unsigned short oport = 0; unsigned short len, block = 0, prevblock = 0; int bcounter = 0; struct tftp_t *tr; struct tftpreq_t tp; int rc; int packetsize = TFTP_DEFAULTSIZE_PACKET; await_reply (AWAIT_QDRAIN, 0, NULL, 0); tp.opcode = htons (TFTP_RRQ); len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d", name, 0, 0, 0, TFTP_MAX_PACKET) + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1); if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; for (;;) { long timeout; #ifdef CONGESTED timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry); #else timeout = rfc2131_sleep_interval (TIMEOUT, retry); #endif if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (! block && retry++ < MAX_TFTP_RETRIES) { if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; continue; } #ifdef CONGESTED if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) { #ifdef MDEBUG grub_printf ("<REXMT>\n"); #endif udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; } #endif break; } tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_printf ("TFTP error %d (%s)\n", ntohs (tr->u.err.errcode), tr->u.err.errmsg); break; } if (tr->opcode == ntohs (TFTP_OACK)) { char *p = tr->u.oack.data, *e; if (prevblock) continue; len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\000' && p < e) { if (! grub_strcmp ("blksize", p)) { p += 8; if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET) goto noak; while (p < e && *p) p++; if (p < e) p++; } else { noak: tp.opcode = htons (TFTP_ERROR); tp.u.err.errcode = 8; len = (grub_sprintf ((char *) tp.u.err.errmsg, "RFC1782 error") + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + sizeof (tp.u.err.errcode) + 1); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs (tr->udp.src), len, &tp); return 0; } } if (p > e) goto noak; block = tp.u.ack.block = 0; } else if (tr->opcode == ntohs (TFTP_DATA)) { len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4; if (len > packetsize) continue; block = ntohs (tp.u.ack.block = tr->u.data.block); } else break; if ((block || bcounter) && (block != prevblock + 1)) tp.u.ack.block = htons (block = prevblock); tp.opcode = htons (TFTP_ACK); oport = ntohs (tr->udp.src); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); if ((unsigned short) (block - prevblock) != 1) continue; prevblock = block; retry = 0; if ((rc = fnc (tr->u.data.download, ++bcounter, len, len < packetsize)) >= 0) return rc; if (len < packetsize) return 1; } return 0; }
int udp_transmit (unsigned long destip, unsigned int srcsock, unsigned int destsock, int len, const void *buf) { struct iphdr *ip; struct udphdr *udp; struct arprequest arpreq; int arpentry, i; int retry; ip = (struct iphdr *) buf; udp = (struct udphdr *) ((unsigned long) buf + sizeof (struct iphdr)); ip->verhdrlen = 0x45; ip->service = 0; ip->len = htons (len); ip->ident = 0; ip->frags = 0; ip->ttl = 60; ip->protocol = IP_UDP; ip->chksum = 0; ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; ip->dest.s_addr = destip; ip->chksum = ipchksum ((unsigned short *) buf, sizeof (struct iphdr)); udp->src = htons (srcsock); udp->dest = htons (destsock); udp->len = htons (len - sizeof (struct iphdr)); udp->chksum = 0; udp->chksum = htons (udpchksum (ip)); if (udp->chksum == 0) udp->chksum = 0xffff; if (destip == IP_BROADCAST) { eth_transmit (broadcast, IP, len, buf); } else { if (((destip & netmask) != (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) && arptable[ARP_GATEWAY].ipaddr.s_addr) destip = arptable[ARP_GATEWAY].ipaddr.s_addr; for (arpentry = 0; arpentry < MAX_ARP; arpentry++) if (arptable[arpentry].ipaddr.s_addr == destip) break; if (arpentry == MAX_ARP) { etherboot_printf ("%@ is not in my arp table!\n", destip); return 0; } for (i = 0; i < ETH_ALEN; i++) if (arptable[arpentry].node[i]) break; if (i == ETH_ALEN) { #ifdef DEBUG grub_printf ("arp request.\n"); #endif arpreq.hwtype = htons (1); arpreq.protocol = htons (IP); arpreq.hwlen = ETH_ALEN; arpreq.protolen = 4; arpreq.opcode = htons (ARP_REQUEST); grub_memmove (arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); grub_memmove (arpreq.sipaddr, (char *) &arptable[ARP_CLIENT].ipaddr, sizeof (in_addr)); grub_memset (arpreq.thwaddr, 0, ETH_ALEN); grub_memmove (arpreq.tipaddr, (char *) &destip, sizeof (in_addr)); for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) { long timeout; eth_transmit (broadcast, ARP, sizeof (arpreq), &arpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, timeout)) goto xmit; if (ip_abort) return 0; } return 0; } xmit: eth_transmit (arptable[arpentry].node, IP, len, buf); } return 1; }
/* Fill the buffer by receiving the data via the TFTP protocol. */ static int buf_fill (int abort) { #ifdef TFTP_DEBUG grub_printf ("buf_fill (%d)\n", abort); #endif while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN)) { struct tftp_t *tr; long timeout; #ifdef CONGESTED timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry); #else timeout = rfc2131_sleep_interval (TIMEOUT, retry); #endif if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (ip_abort) return 0; if (! block && retry++ < MAX_TFTP_RETRIES) { /* Maybe initial request was lost. */ #ifdef TFTP_DEBUG grub_printf ("Maybe initial request was lost.\n"); #endif if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; continue; } #ifdef CONGESTED if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) { /* We resend our last ack. */ # ifdef TFTP_DEBUG grub_printf ("<REXMT>\n"); # endif udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; } #endif /* Timeout. */ return 0; } tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_printf ("TFTP error %d (%s)\n", ntohs (tr->u.err.errcode), tr->u.err.errmsg); return 0; } if (tr->opcode == ntohs (TFTP_OACK)) { char *p = tr->u.oack.data, *e; #ifdef TFTP_DEBUG grub_printf ("OACK "); #endif /* Shouldn't happen. */ if (prevblock) { /* Ignore it. */ grub_printf ("%s:%d: warning: PREVBLOCK != 0 (0x%x)\n", __FILE__, __LINE__, prevblock); continue; } len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\000' && p < e) { if (! grub_strcmp ("blksize", p)) { p += 8; if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET) goto noak; #ifdef TFTP_DEBUG grub_printf ("blksize = %d\n", packetsize); #endif } else if (! grub_strcmp ("tsize", p)) { p += 6; if ((filemax = getdec (&p)) < 0) { filemax = -1; goto noak; } #ifdef TFTP_DEBUG grub_printf ("tsize = %d\n", filemax); #endif } else { noak: #ifdef TFTP_DEBUG grub_printf ("NOAK\n"); #endif tp.opcode = htons (TFTP_ERROR); tp.u.err.errcode = 8; len = (grub_sprintf ((char *) tp.u.err.errmsg, "RFC1782 error") + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + sizeof (tp.u.err.errcode) + 1); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs (tr->udp.src), len, &tp); return 0; } while (p < e && *p) p++; if (p < e) p++; } if (p > e) goto noak; /* This ensures that the packet does not get processed as data! */ block = tp.u.ack.block = 0; } else if (tr->opcode == ntohs (TFTP_DATA)) { #ifdef TFTP_DEBUG grub_printf ("DATA "); #endif len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4; /* Shouldn't happen. */ if (len > packetsize) { /* Ignore it. */ grub_printf ("%s:%d: warning: LEN > PACKETSIZE (0x%x > 0x%x)\n", __FILE__, __LINE__, len, packetsize); continue; } block = ntohs (tp.u.ack.block = tr->u.data.block); } else /* Neither TFTP_OACK nor TFTP_DATA. */ break; if ((block || bcounter) && (block != prevblock + (unsigned short) 1)) /* Block order should be continuous */ tp.u.ack.block = htons (block = prevblock); /* Should be continuous. */ tp.opcode = abort ? htons (TFTP_ERROR) : htons (TFTP_ACK); oport = ntohs (tr->udp.src); #ifdef TFTP_DEBUG grub_printf ("ACK\n"); #endif /* Ack. */ udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); if (abort) { buf_eof = 1; break; } /* Retransmission or OACK. */ if ((unsigned short) (block - prevblock) != 1) /* Don't process. */ continue; prevblock = block; /* Is it the right place to zero the timer? */ retry = 0; /* In GRUB, this variable doesn't play any important role at all, but use it for consistency with Etherboot. */ bcounter++; /* Copy the downloaded data to the buffer. */ grub_memmove (buf + buf_read, tr->u.data.download, len); buf_read += len; /* End of data. */ if (len < packetsize) buf_eof = 1; } return 1; }
int bootp (void) { int retry; #ifndef NO_DHCP_SUPPORT int reqretry; #endif /* ! NO_DHCP_SUPPORT */ struct bootpip_t ip; unsigned long starttime; /* Make sure that an ethernet is probed. */ if (! eth_probe ()) return 0; /* Clear the ready flag. */ network_ready = 0; #ifdef DEBUG grub_printf ("network is ready.\n"); #endif grub_memset (&ip, 0, sizeof (struct bootpip_t)); ip.bp.bp_op = BOOTP_REQUEST; ip.bp.bp_htype = 1; ip.bp.bp_hlen = ETH_ALEN; starttime = currticks (); /* Use lower 32 bits of node address, more likely to be distinct than the time since booting */ grub_memmove (&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); ip.bp.bp_xid = xid += htonl (starttime); grub_memmove (ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); #ifdef DEBUG etherboot_printf ("bp_op = %d\n", ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif #ifdef NO_DHCP_SUPPORT /* Request RFC-style options. */ grub_memmove (ip.bp.bp_vend, rfc1533_cookie, 5); #else /* Request RFC-style options. */ grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); #endif /* ! NO_DHCP_SUPPORT */ for (retry = 0; retry < MAX_BOOTP_RETRIES;) { long timeout; #ifdef DEBUG grub_printf ("retry = %d\n", retry); #endif /* Clear out the Rx queue first. It contains nothing of * interest, except possibly ARP requests from the DHCP/TFTP * server. We use polling throughout Etherboot, so some time * may have passed since we last polled the receive queue, * which may now be filled with broadcast packets. This will * cause the reply to the packets we are about to send to be * lost immediately. Not very clever. */ await_reply (AWAIT_QDRAIN, 0, NULL, 0); udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); timeout = rfc2131_sleep_interval (TIMEOUT, retry++); #ifdef NO_DHCP_SUPPORT if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { network_ready = 1; return 1; } #else /* ! NO_DHCP_SUPPORT */ if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { if (dhcp_reply != DHCPOFFER) { network_ready = 1; return 1; } dhcp_reply = 0; #ifdef DEBUG etherboot_printf ("bp_op = %d\n", (int) ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", (int) ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", (int) ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", (int) ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); grub_memmove (ip.bp.bp_vend + 9, (char *) &dhcp_server, sizeof (in_addr)); grub_memmove (ip.bp.bp_vend + 15, (char *) &dhcp_addr, sizeof (in_addr)); #ifdef DEBUG grub_printf ("errnum = %d\n", errnum); #endif for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES;) { int ret; #ifdef DEBUG grub_printf ("reqretry = %d\n", reqretry); #endif ret = udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); if (! ret) grub_printf ("udp_transmit failed.\n"); dhcp_reply = 0; timeout = rfc2131_sleep_interval (TIMEOUT, reqretry++); if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) if (dhcp_reply == DHCPACK) { network_ready = 1; return 1; } #ifdef DEBUG grub_printf ("dhcp_reply = %d\n", dhcp_reply); #endif if (ip_abort) return 0; } } #endif /* ! NO_DHCP_SUPPORT */ if (ip_abort) return 0; ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC); } /* Timeout. */ return 0; }
static int tftp (const char *name, int (*fnc) (unsigned char *, int, int, int)) { int retry = 0; static unsigned short iport = 2000; unsigned short oport = 0; unsigned short len, block = 0, prevblock = 0; int bcounter = 0; struct tftp_t *tr; struct tftpreq_t tp; int rc; int packetsize = TFTP_DEFAULTSIZE_PACKET; /* Clear out the Rx queue first. It contains nothing of interest, * except possibly ARP requests from the DHCP/TFTP server. We use * polling throughout Etherboot, so some time may have passed since we * last polled the receive queue, which may now be filled with * broadcast packets. This will cause the reply to the packets we are * about to send to be lost immediately. Not very clever. */ await_reply (AWAIT_QDRAIN, 0, NULL, 0); tp.opcode = htons (TFTP_RRQ); len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d", name, 0, 0, 0, TFTP_MAX_PACKET) + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1); if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; for (;;) { long timeout; #ifdef CONGESTED timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry); #else timeout = rfc2131_sleep_interval (TIMEOUT, retry); #endif if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (! block && retry++ < MAX_TFTP_RETRIES) { /* Maybe initial request was lost. */ if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; continue; } #ifdef CONGESTED if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) { /* We resend our last ack. */ #ifdef MDEBUG grub_printf ("<REXMT>\n"); #endif udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; } #endif /* Timeout. */ break; } tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_printf ("TFTP error %d (%s)\n", ntohs (tr->u.err.errcode), tr->u.err.errmsg); break; } if (tr->opcode == ntohs (TFTP_OACK)) { char *p = tr->u.oack.data, *e; /* Shouldn't happen. */ if (prevblock) /* Ignore it. */ continue; len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\000' && p < e) { if (! grub_strcmp ("blksize", p)) { p += 8; if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET) goto noak; while (p < e && *p) p++; if (p < e) p++; } else { noak: tp.opcode = htons (TFTP_ERROR); tp.u.err.errcode = 8; len = (grub_sprintf ((char *) tp.u.err.errmsg, "RFC1782 error") + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + sizeof (tp.u.err.errcode) + 1); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs (tr->udp.src), len, &tp); return 0; } } if (p > e) goto noak; /* This ensures that the packet does not get processed as data! */ block = tp.u.ack.block = 0; } else if (tr->opcode == ntohs (TFTP_DATA)) { len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4; /* Shouldn't happen. */ if (len > packetsize) /* Ignore it. */ continue; block = ntohs (tp.u.ack.block = tr->u.data.block); } else /* Neither TFTP_OACK nor TFTP_DATA. */ break; if ((block || bcounter) && (block != prevblock + 1)) /* Block order should be continuous */ tp.u.ack.block = htons (block = prevblock); /* Should be continuous. */ tp.opcode = htons (TFTP_ACK); oport = ntohs (tr->udp.src); /* Ack. */ udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); if ((unsigned short) (block - prevblock) != 1) /* Retransmission or OACK, don't process via callback * and don't change the value of prevblock. */ continue; prevblock = block; /* Is it the right place to zero the timer? */ retry = 0; if ((rc = fnc (tr->u.data.download, ++bcounter, len, len < packetsize)) >= 0) return rc; /* End of data. */ if (len < packetsize) return 1; } return 0; }
/*************************************************************************** * NFS_READLINK (AH 2003-07-14) * This procedure is called when read of the first block fails - * this probably happens when it's a directory or a symlink * In case of successful readlink(), the dirname is manipulated, * so that inside the nfs() function a recursion can be done. **************************************************************************/ static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh, int sport) { struct rpc_t buf, *rpc; unsigned long id; long *p; int retries; int pathlen = strlen(path); id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_NFS); buf.u.call.vers = htonl(2); /* nfsd is version 2 */ buf.u.call.proc = htonl(NFS_READLINK); p = rpc_add_credentials((long *)buf.u.call.data); memcpy(p, nfh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); udp_transmit(arptable[server].ipaddr.s_addr, sport, port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, sport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus || rpc->u.reply.data[0]) { rpc_printerror(rpc); if (rpc->u.reply.rstatus) { /* RPC failed, no verifier, data[0] */ return -9999; } if (rpc->u.reply.astatus) { /* RPC couldn't decode parameters */ return -9998; } return -ntohl(rpc->u.reply.data[0]); } else { // It *is* a link. // If it's a relative link, append everything to dirname, filename TOO! retries = strlen ( (char *)(&(rpc->u.reply.data[2]) )); if ( *((char *)(&(rpc->u.reply.data[2]))) != '/' ) { path[pathlen++] = '/'; while ( ( retries + pathlen ) > 298 ) { retries--; } if ( retries > 0 ) { memcpy(path + pathlen, &(rpc->u.reply.data[2]), retries + 1); } else { retries = 0; } path[pathlen + retries] = 0; } else { // Else make it the only path. if ( retries > 298 ) { retries = 298; } memcpy ( path, &(rpc->u.reply.data[2]), retries + 1 ); path[retries] = 0; } return 0; } } } return -1; }