📄 nic.c
字号:
void rx_qdrain(void){ /* 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 DOWNLOAD_PROTO_TFTP/**************************************************************************TFTP - Download extended BOOTP data, or kernel image**************************************************************************/static int await_tftp(int ival, void *ptr __unused, unsigned short ptype __unused, struct iphdr *ip, struct udphdr *udp){ if (!udp) { return 0; } if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr) return 0; if (ntohs(udp->dest) != ival) return 0; return 1;}int tftp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned 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; rx_qdrain(); tp.opcode = htons(TFTP_RRQ); /* Warning: the following assumes the layout of bootp_t. But that's fixed by the IP, UDP and BOOTP specs. */ len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d", name, 0, 0, 0, TFTP_MAX_PACKET) + 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 printf("<REXMT>\n");#endif udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; }#endif break; /* timeout */ } tr = (struct tftp_t *)&nic.packet[ETH_HLEN]; if (tr->opcode == ntohs(TFTP_ERROR)) { printf("TFTP error %d (%s)\n", ntohs(tr->u.err.errcode), tr->u.err.errmsg); break; } if (tr->opcode == ntohs(TFTP_OACK)) { const char *p = tr->u.oack.data, *e; if (prevblock) /* shouldn't happen */ continue; /* ignore it */ len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\0' && p < e) { if (!strcasecmp("blksize", p)) { p += 8; if ((packetsize = strtoul(p, &p, 10)) < 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;/* * Warning: the following assumes the layout of bootp_t. * But that's fixed by the IP, UDP and BOOTP specs. */ len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +/* * Normally bad form to omit the format string, but in this case * the string we are copying from is fixed. sprintf is just being * used as a strcpy and strlen. */ sprintf((char *)tp.u.err.errmsg, "RFC1782 error") + 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; /* this ensures, that */ /* the packet does not get */ /* processed as data! */ } else if (tr->opcode == htons(TFTP_DATA)) { len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4; if (len > packetsize) /* shouldn't happen */ continue; /* ignore it */ block = ntohs(tp.u.ack.block = tr->u.data.block); } else {/* neither TFTP_OACK nor TFTP_DATA */ break; } if ((block || bcounter) && (block != (unsigned short)(prevblock+1))) { /* Block order should be continuous */ 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); /* ack */ 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; retry = 0; /* It's the right place to zero the timer? */ if ((rc = fnc(tr->u.data.download, ++bcounter, len, len < packetsize)) <= 0) return(rc); if (len < packetsize) { /* End of data --- fnc should not have returned */ printf("tftp download complete, but\n"); return (1); } } return (0);}#endif /* DOWNLOAD_PROTO_TFTP */#ifdef RARP_NOT_BOOTP/**************************************************************************RARP - Get my IP address and load information**************************************************************************/static int await_rarp(int ival, void *ptr, unsigned short ptype, struct iphdr *ip, struct udphdr *udp){ struct arprequest *arpreply; if (ptype != RARP) return 0; if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest)) return 0; arpreply = (struct arprequest *)&nic.packet[ETH_HLEN]; if (arpreply->opcode != htons(RARP_REPLY)) return 0; if ((arpreply->opcode == htons(RARP_REPLY)) && (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0)) { memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN); memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr)); memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr)); return 1; } return 0;}static int rarp(void){ int retry; /* arp and rarp requests share the same packet structure. */ struct arprequest rarpreq; 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); memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); /* sipaddr is already zeroed out */ memcpy(&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 (retry < MAX_ARP_RETRIES) { (void)sprintf(KERNEL_BUF, DEFAULT_KERNELPATH, arptable[ARP_CLIENT].ipaddr); return (1); } return (0);}#else/**************************************************************************BOOTP - Get my IP address and load information**************************************************************************/static int await_bootp(int ival __unused, void *ptr __unused, unsigned short ptype __unused, struct iphdr *ip __unused, struct udphdr *udp){ struct bootp_t *bootpreply; if (!udp) { return 0; } bootpreply = (struct bootp_t *)&nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)]; if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) + #ifdef NO_DHCP_SUPPORT sizeof(struct bootp_t)#else sizeof(struct bootp_t) - DHCP_OPT_LEN#endif /* NO_DHCP_SUPPORT */ ) { return 0; } if (udp->dest != htons(BOOTP_CLIENT)) return 0; if (bootpreply->bp_op != BOOTP_REPLY) return 0; if (bootpreply->bp_xid != xid) return 0; if (memcmp(&bootpreply->bp_siaddr, &zeroIP, sizeof(in_addr)) == 0) return 0;#ifndef DEFAULT_BOOTFILE if (bootpreply->bp_file[0] == '\0') { printf("F?"); /* No filename in offer */ return 0; }#endif if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) && (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) { return 0; } arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;#ifndef NO_DHCP_SUPPORT dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;#endif /* NO_DHCP_SUPPORT */ netmask = default_netmask(); arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr; memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */ arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr; memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */ /* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */ memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t)); decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, 0,#ifdef NO_DHCP_SUPPORT BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, #else DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, #endif /* NO_DHCP_SUPPORT */ 1);#ifdef REQUIRE_VCI_ETHERBOOT if (!vci_etherboot) return (0);#endif return(1);}static int bootp(void){ int retry;#ifndef NO_DHCP_SUPPORT int reqretry;#endif /* NO_DHCP_SUPPORT */ struct bootpip_t ip; unsigned long starttime; unsigned char *bp_vend;#ifndef NO_DHCP_SUPPORT dhcp_machine_info[4] = nic.dev.devid.bus_type; dhcp_machine_info[5] = nic.dev.devid.vendor_id & 0xff; dhcp_machine_info[6] = ((nic.dev.devid.vendor_id) >> 8) & 0xff; dhcp_machine_info[7] = nic.dev.devid.device_id & 0xff; dhcp_machine_info[8] = ((nic.dev.devid.device_id) >> 8) & 0xff;#endif /* NO_DHCP_SUPPORT */ 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 */ memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); ip.bp.bp_xid = xid += htonl(starttime); memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);#ifdef NO_DHCP_SUPPORT memcpy(ip.bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */#else memcpy(ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */ memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); /* Append machine_info to end, in encapsulated option */ bp_vend = ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover; memcpy(bp_vend, dhcp_machine_info, DHCP_MACHINE_INFO_SIZE); bp_vend += DHCP_MACHINE_INFO_SIZE; *bp_vend++ = RFC1533_END;#endif /* NO_DHCP_SUPPORT */ for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { long timeout; rx_qdrain(); 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)) return(1);#else if (await_reply(await_bootp, 0, NULL, timeout)) { /* If not a DHCPOFFER then must be just a BOOTP reply, be backward compatible with BOOTP then */ if (dhcp_reply != DHCPOFFER) return(1); dhcp_reply = 0; memcpy(ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); /* Beware: the magic numbers 9 and 15 depend on the layout of dhcprequest */ memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr)); memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr)); bp_vend = ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcprequest; /* Append machine_info to end, in encapsulated option */ memcpy(bp_vend, dhcp_machine_info, DHCP_MACHINE_INFO_SIZE); bp_vend += DHCP_MACHINE_INFO_SIZE; *bp_vend++ = RFC1533_END; for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) { udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof(struct bootpip_t), &ip); dhcp_reply=0; timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++); if (await_reply(await_bootp, 0, NULL, timeout)) if (dhcp_reply == DHCPACK) return(1); } }#endif /* NO_DHCP_SUPPORT */ ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC); } return(0);}#endif /* RARP_NOT_BOOTP */static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp){ struct udp_pseudo_hdr pseudo; uint16_t checksum; /* Compute the pseudo header */ pseudo.src.s_addr = ip->src.s_addr; pseudo.dest.s_addr = ip->dest.s_addr; pseudo.unused = 0; pseudo.protocol = IP_UDP; pseudo.len = udp->len; /* Sum the pseudo header */ checksum = ipchksum(&pseudo, 12); /* Sum the rest of the udp packet */ checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len))); return checksum;}#ifdef MULTICAST_LEVEL2static void send_igmp_reports(unsigned long now){ int i; for(i = 0; i < MAX_IGMP; i++) { if (igmptable[i].time && (now >= igmptable[i].time)) { struct igmp_ip_t igmp; igmp.router_alert[0] = 0x94; igmp.router_alert[1] = 0x04; igmp.router_alert[2] = 0; igmp.router_alert[3] = 0; build_ip_hdr(igmptable[i].group.s_addr, 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp); igmp.igmp.type = IGMPv2_REPORT; if (last_igmpv1 && (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) { igmp.igmp.type = IGMPv1_REPORT; } igmp.igmp.response_time = 0; igmp.igmp.chksum = 0; igmp.igmp.group.s_addr = igmptable[i].group.s_addr; igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp)); ip_transmit(sizeof(igmp), &igmp);#ifdef MDEBUG printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -