📄 nic.c
字号:
/**************************************************************************Etherboot - Network Bootstrap ProgramLiterature dealing with the network protocols: ARP - RFC826 RARP - RFC903 IP - RFC791 UDP - RFC768 BOOTP - RFC951, RFC2132 (vendor extensions) DHCP - RFC2131, RFC2132 (options) TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize) RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper) NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented) IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171**************************************************************************/#include "etherboot.h"#include "nic.h"#include "elf.h" /* FOR EM_CURRENT */struct arptable_t arptable[MAX_ARP];#if MULTICAST_LEVEL2unsigned long last_igmpv1 = 0;struct igmptable_t igmptable[MAX_IGMP];#endif/* Currently no other module uses rom, but it is available */struct rom_info rom;static unsigned long netmask;/* Used by nfs.c */char *hostname = "";int hostnamelen = 0;static uint32_t xid;unsigned char *end_of_rfc1533 = NULL;static int vendorext_isvalid;static const unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* 銭th */static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };static const in_addr zeroIP = { 0L };struct bootpd_t bootp_data;#ifdef NO_DHCP_SUPPORTstatic unsigned char rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END };#else /* !NO_DHCP_SUPPORT */static int dhcp_reply;static in_addr dhcp_server = { 0L };static in_addr dhcp_addr = { 0L };static unsigned char rfc1533_cookie[] = { RFC1533_COOKIE };#define DHCP_MACHINE_INFO_SIZE (sizeof dhcp_machine_info)static unsigned char dhcp_machine_info[] = { /* Our enclosing DHCP tag */ RFC1533_VENDOR_ETHERBOOT_ENCAP, 11, /* Our boot device */ RFC1533_VENDOR_NIC_DEV_ID, 5, PCI_BUS_TYPE, 0, 0, 0, 0, /* Our current architecture */ RFC1533_VENDOR_ARCH, 2, EM_CURRENT & 0xff, (EM_CURRENT >> 8) & 0xff,#ifdef EM_CURRENT_64 /* The 64bit version of our current architecture */ RFC1533_VENDOR_ARCH, 2, EM_CURRENT_64 & 0xff, (EM_CURRENT_64 >> 8) & 0xff,#undef DHCP_MACHINE_INFO_SIZE#define DHCP_MACHINE_INFO_SIZE (sizeof(dhcp_machine_info) - (EM_CURRENT_64_PRESENT? 0: 4))#endif /* EM_CURRENT_64 */};static const unsigned char dhcpdiscover[] = { RFC2132_MSG_TYPE,1,DHCPDISCOVER, RFC2132_MAX_SIZE,2, /* request as much as we can */ ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, RFC2132_VENDOR_CLASS_ID,13,'E','t','h','e','r','b','o','o','t', '-',VERSION_MAJOR+'0','.',VERSION_MINOR+'0', RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY, RFC1533_HOSTNAME,RFC1533_VENDOR};static const unsigned char dhcprequest [] = { RFC2132_MSG_TYPE,1,DHCPREQUEST, RFC2132_SRV_ID,4,0,0,0,0, RFC2132_REQ_ADDR,4,0,0,0,0, RFC2132_MAX_SIZE,2, /* request as much as we can */ ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, RFC2132_VENDOR_CLASS_ID,13,'E','t','h','e','r','b','o','o','t', '-',VERSION_MAJOR+'0','.',VERSION_MINOR+'0', /* request parameters */ RFC2132_PARAM_LIST,#ifdef IMAGE_FREEBSD /* 5 standard + 7 vendortags + 8 motd + 16 menu items */ 5 + 7 + 8 + 16,#else /* 5 standard + 6 vendortags + 8 motd + 16 menu items */ 5 + 6 + 8 + 16,#endif /* Standard parameters */ RFC1533_NETMASK, RFC1533_GATEWAY, RFC1533_HOSTNAME,RFC1533_VENDOR, RFC1533_ROOTPATH, /* only passed to the booted image */ /* Etherboot vendortags */ RFC1533_VENDOR_MAGIC, RFC1533_VENDOR_ADDPARM, RFC1533_VENDOR_ETHDEV, RFC1533_VENDOR_ETHERBOOT_ENCAP,#ifdef IMAGE_FREEBSD RFC1533_VENDOR_HOWTO, RFC1533_VENDOR_KERNEL_ENV,#endif RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION, /* 8 MOTD entries */ RFC1533_VENDOR_MOTD, RFC1533_VENDOR_MOTD+1, RFC1533_VENDOR_MOTD+2, RFC1533_VENDOR_MOTD+3, RFC1533_VENDOR_MOTD+4, RFC1533_VENDOR_MOTD+5, RFC1533_VENDOR_MOTD+6, RFC1533_VENDOR_MOTD+7, /* 16 image entries */ RFC1533_VENDOR_IMG, RFC1533_VENDOR_IMG+1, RFC1533_VENDOR_IMG+2, RFC1533_VENDOR_IMG+3, RFC1533_VENDOR_IMG+4, RFC1533_VENDOR_IMG+5, RFC1533_VENDOR_IMG+6, RFC1533_VENDOR_IMG+7, RFC1533_VENDOR_IMG+8, RFC1533_VENDOR_IMG+9, RFC1533_VENDOR_IMG+10, RFC1533_VENDOR_IMG+11, RFC1533_VENDOR_IMG+12, RFC1533_VENDOR_IMG+13, RFC1533_VENDOR_IMG+14, RFC1533_VENDOR_IMG+15,};#ifdef REQUIRE_VCI_ETHERBOOTint vci_etherboot;#endif#endif /* NO_DHCP_SUPPORT */static int dummy(void *unused __unused){ return (0);}/* Careful. We need an aligned buffer to avoid problems on machines * that care about alignment. To trivally align the ethernet data * (the ip hdr and arp requests) we offset the packet by 2 bytes. * leaving the ethernet data 16 byte aligned. Beyond this * we use memmove but this makes the common cast simple and fast. */static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;struct nic nic ={ { 0, /* dev.disable */ { 0, 0, PCI_BUS_TYPE, }, /* dev.devid */ 0, /* index */ 0, /* type */ PROBE_FIRST, /* how_pobe */ PROBE_NONE, /* to_probe */ 0, /* failsafe */ 0, /* type_index */ {}, /* state */ }, (int (*)(struct nic *))dummy, /* poll */ (void (*)(struct nic *, const char *, unsigned int, unsigned int, const char *))dummy, /* transmit */ 0, /* flags */ &rom, /* rom_info */ arptable[ARP_CLIENT].node, /* node_addr */ packet + ETH_DATA_ALIGN, /* packet */ 0, /* packetlen */ 0, /* priv_data */};#ifdef RARP_NOT_BOOTPstatic int rarp(void);#elsestatic int bootp(void);#endifstatic unsigned short udpchksum(struct iphdr *ip, struct udphdr *udp);int eth_probe(struct dev *dev){ return probe(dev);}int eth_poll(void){ return ((*nic.poll)(&nic));}void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p){ (*nic.transmit)(&nic, d, t, s, p); if (t == IP) twiddle();}void eth_disable(void){#ifdef MULTICAST_LEVEL2 int i; for(i = 0; i < MAX_IGMP; i++) { leave_group(i); }#endif disable(&nic.dev);}/* * Find out what our boot parameters are */int eth_load_configuration(struct dev *dev __unused){ int server_found; /* Find a server to get BOOTP reply from */#ifdef RARP_NOT_BOOTP printf("Searching for server (RARP)...\n");#else#ifndef NO_DHCP_SUPPORT printf("Searching for server (DHCP)...\n");#else printf("Searching for server (BOOTP)...\n");#endif#endif#ifdef RARP_NOT_BOOTP server_found = rarp();#else server_found = bootp();#endif if (!server_found) { printf("No Server found\n"); longjmp(restart_etherboot, -1); } return 0;}/**************************************************************************LOAD - Try to get booted**************************************************************************/int eth_load(struct dev *dev __unused){ const char *kernel; printf("Me: %@, Server: %@", arptable[ARP_CLIENT].ipaddr.s_addr, arptable[ARP_SERVER].ipaddr.s_addr); if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr) printf(", Relay: %@", BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr); if (arptable[ARP_GATEWAY].ipaddr.s_addr) printf(", Gateway %@", arptable[ARP_GATEWAY].ipaddr.s_addr); putchar('\n');#ifdef MDEBUG printf("\n=>>"); getchar();#endif /* Now use TFTP to load file */#ifdef DOWNLOAD_PROTO_NFS rpc_init();#endif#ifdef DEFAULT_BOOTFILE kernel = KERNEL_BUF[0] != '\0' ? KERNEL_BUF : DEFAULT_BOOTFILE;#else kernel = KERNEL_BUF;#endif loadkernel(kernel); /* We don't return except on error */ printf("Unable to load file.\n"); interruptible_sleep(2); /* lay off the server for a while */ longjmp(restart_etherboot, -1);}/**************************************************************************DEFAULT_NETMASK - Return default netmask for IP address**************************************************************************/static inline unsigned long default_netmask(void){ int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24; if (net <= 127) return(htonl(0xff000000)); else if (net < 192) return(htonl(0xffff0000)); else return(htonl(0xffffff00));}/**************************************************************************IP_TRANSMIT - Send an IP datagram**************************************************************************/static int await_arp(int ival, void *ptr, unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused){ struct arprequest *arpreply; if (ptype != ARP) return 0; if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest)) return 0; arpreply = (struct arprequest *)&nic.packet[ETH_HLEN]; if (arpreply->opcode != htons(ARP_REPLY)) return 0; if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0) return 0; memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN); return 1;}int ip_transmit(int len, const void *buf){ unsigned long destip; struct iphdr *ip; struct arprequest arpreq; int arpentry, i; int retry; ip = (struct iphdr *)buf; destip = ip->dest.s_addr; if (destip == IP_BROADCAST) { eth_transmit(broadcast, IP, len, buf);#ifdef MULTICAST_LEVEL1 } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) { unsigned char multicast[6]; unsigned long hdestip; hdestip = ntohl(destip); multicast[0] = 0x01; multicast[1] = 0x00; multicast[2] = 0x5e; multicast[3] = (hdestip >> 16) & 0x7; multicast[4] = (hdestip >> 8) & 0xff; multicast[5] = hdestip & 0xff; eth_transmit(multicast, IP, len, buf);#endif } 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) { 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) { /* Need to do arp request */ arpreq.hwtype = htons(1); arpreq.protocol = htons(IP); arpreq.hwlen = ETH_ALEN; arpreq.protolen = 4; arpreq.opcode = htons(ARP_REQUEST); memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr)); memset(arpreq.thwaddr, 0, ETH_ALEN); memcpy(arpreq.tipaddr, &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; } return(0); }xmit: eth_transmit(arptable[arpentry].node, IP, len, buf); } return 1;}void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len, int len, const void *buf){ struct iphdr *ip; ip = (struct iphdr *)buf; ip->verhdrlen = 0x45; ip->verhdrlen += (option_len/4); ip->service = 0; ip->len = htons(len); ip->ident = 0; ip->frags = 0; /* Should we set don't fragment? */ ip->ttl = ttl; ip->protocol = protocol; ip->chksum = 0; ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; ip->dest.s_addr = destip; ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);}void build_udp_hdr(unsigned long destip, unsigned int srcsock, unsigned int destsock, int ttl, int len, const void *buf){ struct iphdr *ip; struct udphdr *udp; ip = (struct iphdr *)buf; build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf); udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr)); udp->src = htons(srcsock); udp->dest = htons(destsock); udp->len = htons(len - sizeof(struct iphdr)); udp->chksum = 0; if ((udp->chksum = udpchksum(ip, udp)) == 0) udp->chksum = 0xffff;}/**************************************************************************UDP_TRANSMIT - Send an UDP datagram**************************************************************************/int udp_transmit(unsigned long destip, unsigned int srcsock, unsigned int destsock, int len, const void *buf){ build_udp_hdr(destip, srcsock, destsock, 60, len, buf); return ip_transmit(len, buf);}/**************************************************************************QDRAIN - clear the nic's receive queue**************************************************************************/static int await_qdrain(int ival __unused, void *ptr __unused, unsigned short ptype __unused, struct iphdr *ip __unused, struct udphdr *udp __unused){ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -