📄 main.c
字号:
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;}/**************************************************************************RARP - Get my IP address and load information**************************************************************************/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;}/**************************************************************************BOOTP - Get my IP address and load information**************************************************************************/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;}/**************************************************************************UDPCHKSUM - Checksum UDP Packet (one of the rare cases when assembly is actually simpler...) RETURNS: checksum, 0 on checksum error. This allows for using the same routine for RX and TX summing: RX if (packet->udp.chksum && udpchksum(packet)) error("checksum error"); TX packet->udp.chksum=0; if (0==(packet->udp.chksum=udpchksum(packet))) packet->upd.chksum=0xffff;**************************************************************************/static inline voiddosum (unsigned short *start, unsigned int len, unsigned short *sum){ __asm__ __volatile__ ("clc\n" "1:\tlodsw\n\t" "xchg %%al,%%ah\n\t" /* convert to host byte order */ "adcw %%ax,%0\n\t" /* add carry of previous iteration */ "loop 1b\n\t" "adcw $0,%0" /* add carry of last iteration */ : "=b" (*sum), "=S"(start), "=c"(len) : "0"(*sum), "1"(start), "2"(len) : "ax", "cc" );}/* UDP sum: * proto, src_ip, dst_ip, udp_dport, udp_sport, 2*udp_len, payload */static unsigned shortudpchksum (struct iphdr *packet){ int len = ntohs (packet->len); unsigned short rval; /* add udplength + protocol number */ rval = (len - sizeof (struct iphdr)) + IP_UDP; /* pad to an even number of bytes */ if (len % 2) { ((char *) packet)[len++] = 0; } /* sum over src/dst ipaddr + udp packet */ len -= (char *) &packet->src - (char *) packet; dosum ((unsigned short *) &packet->src, len >> 1, &rval); /* take one's complement */ return ~rval;}/**************************************************************************AWAIT_REPLY - Wait until we get a response for our request**************************************************************************/int await_reply (int type, int ival, void *ptr, int timeout){ unsigned long time; struct iphdr *ip; struct udphdr *udp; struct arprequest *arpreply; struct bootp_t *bootpreply; unsigned short ptype; unsigned int protohdrlen = (ETH_HLEN + sizeof (struct iphdr) + sizeof (struct udphdr)); /* Clear the abort flag. */ ip_abort = 0; time = timeout + currticks (); /* The timeout check is done below. The timeout is only checked if * there is no packet in the Rx queue. This assumes that eth_poll() * needs a negligible amount of time. */ for (;;) { if (eth_poll ()) { /* We have something! */ /* Check for ARP - No IP hdr. */ if (nic.packetlen >= ETH_HLEN) { ptype = (((unsigned short) nic.packet[12]) << 8 | ((unsigned short) nic.packet[13])); } else /* What else could we do with it? */ continue; if (nic.packetlen >= ETH_HLEN + sizeof (struct arprequest) && ptype == ARP) { unsigned long tmp; arpreply = (struct arprequest *) &nic.packet[ETH_HLEN]; if (arpreply->opcode == htons (ARP_REPLY) && ! grub_memcmp (arpreply->sipaddr, ptr, sizeof (in_addr)) && type == AWAIT_ARP)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -