/* * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet */ static void store_net_params(struct bootp_hdr *bp) { #if !defined(CONFIG_BOOTP_SERVERIP) struct in_addr tmp_ip; net_copy_ip(&tmp_ip, &bp->bp_siaddr); if (tmp_ip.s_addr != 0) net_copy_ip(&net_server_ip, &bp->bp_siaddr); memcpy(net_server_ethaddr, ((struct ethernet_hdr *)net_rx_packet)->et_src, 6); if (strlen(bp->bp_file) > 0) copy_filename(net_boot_file_name, bp->bp_file, sizeof(net_boot_file_name)); debug("net_boot_file_name: %s\n", net_boot_file_name); /* Propagate to environment: * don't delete exising entry when BOOTP / DHCP reply does * not contain a new value */ if (*net_boot_file_name) setenv("bootfile", net_boot_file_name); #endif net_copy_ip(&net_ip, &bp->bp_yiaddr); }
void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) { struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src; struct in_addr src_ip; int eth_hdr_size; switch (icmph->type) { case ICMP_ECHO_REPLY: src_ip = net_read_ip((void *)&ip->ip_src); if (src_ip.s_addr == net_ping_ip.s_addr) net_set_state(NETLOOP_SUCCESS); return; case ICMP_ECHO_REQUEST: eth_hdr_size = net_update_ether(et, et->et_src, PROT_IP); debug_cond(DEBUG_DEV_PKT, "Got ICMP ECHO REQUEST, return %d bytes\n", eth_hdr_size + len); ip->ip_sum = 0; ip->ip_off = 0; net_copy_ip((void *)&ip->ip_dst, &ip->ip_src); net_copy_ip((void *)&ip->ip_src, &net_ip); ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); icmph->type = ICMP_ECHO_REPLY; icmph->checksum = 0; icmph->checksum = compute_ip_checksum(icmph, len - IP_HDR_SIZE); net_send_packet((uchar *)et, eth_hdr_size + len); return; /* default: return;*/ } }
static void dhcp_send_request_packet(struct bootp *bp_offer) { struct bootp *bp; int extlen; IPaddr_t OfferedIP; unsigned char *payload = net_udp_get_payload(dhcp_con); debug("%s: Sending DHCPREQUEST\n", __func__); bp = (struct bootp *)payload; bp->bp_op = OP_BOOTREQUEST; bp->bp_htype = HWT_ETHER; bp->bp_hlen = HWL_ETHER; bp->bp_hops = 0; /* FIXME what is this? */ // bp->bp_secs = htons(get_timer(0) / CFG_HZ); net_copy_ip(&bp->bp_ciaddr, &bp_offer->bp_ciaddr); /* both in network byte order */ net_copy_ip(&bp->bp_yiaddr, &bp_offer->bp_yiaddr); net_copy_ip(&bp->bp_siaddr, &bp_offer->bp_siaddr); /* * RFC3046 requires Relay Agents to discard packets with * nonzero and offered giaddr */ net_write_ip(&bp->bp_giaddr, 0); memcpy(bp->bp_chaddr, dhcp_con->et->et_src, 6); /* * ID is the id of the OFFER packet */ net_copy_uint32(&bp->bp_id, &bp_offer->bp_id); /* * Copy options from OFFER packet if present */ net_copy_ip(&OfferedIP, &bp->bp_yiaddr); extlen = dhcp_extended((u8 *)bp->bp_vend, DHCP_REQUEST, net_dhcp_server_ip, OfferedIP); debug("Transmitting DHCPREQUEST packet\n"); net_udp_send(dhcp_con, sizeof(*bp) + extlen); }
static void copy_ip_handle(struct dhcp_opt *opt, unsigned char *popt, int optlen) { net_copy_ip(opt->data, popt); };
static int sb_eth_send(struct udevice *dev, void *packet, int length) { struct eth_sandbox_priv *priv = dev_get_priv(dev); struct ethernet_hdr *eth = packet; debug("eth_sandbox: Send packet %d\n", length); if (dev->seq >= 0 && dev->seq < ARRAY_SIZE(disabled) && disabled[dev->seq]) return 0; if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE; if (ntohs(arp->ar_op) == ARPOP_REQUEST) { struct ethernet_hdr *eth_recv; struct arp_hdr *arp_recv; /* store this as the assumed IP of the fake host */ priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa); /* Formulate a fake response */ eth_recv = (void *)priv->recv_packet_buffer; memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); eth_recv->et_protlen = htons(PROT_ARP); arp_recv = (void *)priv->recv_packet_buffer + ETHER_HDR_SIZE; arp_recv->ar_hrd = htons(ARP_ETHER); arp_recv->ar_pro = htons(PROT_IP); arp_recv->ar_hln = ARP_HLEN; arp_recv->ar_pln = ARP_PLEN; arp_recv->ar_op = htons(ARPOP_REPLY); memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN); net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr); memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa); priv->recv_packet_length = ETHER_HDR_SIZE + ARP_HDR_SIZE; } } else if (ntohs(eth->et_protlen) == PROT_IP) { struct ip_udp_hdr *ip = packet + ETHER_HDR_SIZE; if (ip->ip_p == IPPROTO_ICMP) { struct icmp_hdr *icmp = (struct icmp_hdr *)&ip->udp_src; if (icmp->type == ICMP_ECHO_REQUEST) { struct ethernet_hdr *eth_recv; struct ip_udp_hdr *ipr; struct icmp_hdr *icmpr; /* reply to the ping */ memcpy(priv->recv_packet_buffer, packet, length); eth_recv = (void *)priv->recv_packet_buffer; ipr = (void *)priv->recv_packet_buffer + ETHER_HDR_SIZE; icmpr = (struct icmp_hdr *)&ipr->udp_src; memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); ipr->ip_sum = 0; ipr->ip_off = 0; net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src); net_write_ip((void *)&ipr->ip_src, priv->fake_host_ipaddr); ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); icmpr->type = ICMP_ECHO_REPLY; icmpr->checksum = 0; icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE); priv->recv_packet_length = length; } } } return 0; }
static void dhcp_options_process(unsigned char *popt, struct bootp *bp) { unsigned char *end = popt + sizeof(*bp) + OPT_SIZE; int oplen; IPaddr_t ip; char str[256]; while (popt < end && *popt != 0xff) { oplen = *(popt + 1); switch (*popt) { case 1: ip = net_read_ip(popt + 2); net_set_netmask(ip); break; case 3: ip = net_read_ip(popt + 2); net_set_gateway(ip); break; case 6: ip = net_read_ip(popt + 2); setenv_ip("nameserver", ip); break; case 12: memcpy(str, popt + 2, oplen); str[oplen] = 0; setenv("hostname", str); break; case 15: memcpy(str, popt + 2, oplen); str[oplen] = 0; setenv("domainname", str); break; case 17: memcpy(str, popt + 2, oplen); str[oplen] = 0; setenv("rootpath", str); break; case 51: net_copy_uint32 (&dhcp_leasetime, (uint32_t *)(popt + 2)); break; case 53: /* Ignore Message Type Option */ break; case 54: net_copy_ip(&net_dhcp_server_ip, (popt + 2)); break; case 58: /* Ignore Renewal Time Option */ break; case 59: /* Ignore Rebinding Time Option */ break; case 66: /* Ignore TFTP server name */ break; case 67: /* vendor opt bootfile */ /* * I can't use dhcp_vendorex_proc here because I need * to write into the bootp packet - even then I had to * pass the bootp packet pointer into here as the * second arg */ memcpy(str, popt + 2, oplen); str[oplen] = 0; if (bp->bp_file[0] == '\0') { /* * only use vendor boot file if we didn't * receive a boot file in the main non-vendor * part of the packet - god only knows why * some vendors chose not to use this perfectly * good spot to store the boot file (join on * Tru64 Unix) it seems mind bogglingly crazy * to me */ printf("*** WARNING: using vendor " "optional boot file\n"); setenv("bootfile", str); } break; default: #ifdef CONFIG_BOOTP_VENDOREX if (dhcp_vendorex_proc (popt)) break; #endif debug("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt); break; } popt += oplen + 2; /* Process next option */ } }
static void bootp_process_vendor_field(u8 *ext) { int size = *(ext + 1); debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext, *(ext + 1)); net_boot_file_expected_size_in_blocks = 0; switch (*ext) { /* Fixed length fields */ case 1: /* Subnet mask */ if (net_netmask.s_addr == 0) net_copy_ip(&net_netmask, (struct in_addr *)(ext + 2)); break; case 2: /* Time offset - Not yet supported */ break; /* Variable length fields */ case 3: /* Gateways list */ if (net_gateway.s_addr == 0) net_copy_ip(&net_gateway, (struct in_addr *)(ext + 2)); break; case 4: /* Time server - Not yet supported */ break; case 5: /* IEN-116 name server - Not yet supported */ break; case 6: if (net_dns_server.s_addr == 0) net_copy_ip(&net_dns_server, (struct in_addr *)(ext + 2)); #if defined(CONFIG_BOOTP_DNS2) if ((net_dns_server2.s_addr == 0) && (size > 4)) net_copy_ip(&net_dns_server2, (struct in_addr *)(ext + 2 + 4)); #endif break; case 7: /* Log server - Not yet supported */ break; case 8: /* Cookie/Quote server - Not yet supported */ break; case 9: /* LPR server - Not yet supported */ break; case 10: /* Impress server - Not yet supported */ break; case 11: /* RPL server - Not yet supported */ break; case 12: /* Host name */ if (net_hostname[0] == 0) { size = truncate_sz("Host Name", sizeof(net_hostname), size); memcpy(&net_hostname, ext + 2, size); net_hostname[size] = 0; } break; case 13: /* Boot file size */ if (size == 2) net_boot_file_expected_size_in_blocks = ntohs(*(ushort *)(ext + 2)); else if (size == 4) net_boot_file_expected_size_in_blocks = ntohl(*(ulong *)(ext + 2)); break; case 14: /* Merit dump file - Not yet supported */ break; case 15: /* Domain name - Not yet supported */ break; case 16: /* Swap server - Not yet supported */ break; case 17: /* Root path */ if (net_root_path[0] == 0) { size = truncate_sz("Root Path", sizeof(net_root_path), size); memcpy(&net_root_path, ext + 2, size); net_root_path[size] = 0; } break; case 18: /* Extension path - Not yet supported */ /* * This can be used to send the information of the * vendor area in another file that the client can * access via TFTP. */ break; /* IP host layer fields */ case 40: /* NIS Domain name */ if (net_nis_domain[0] == 0) { size = truncate_sz("NIS Domain Name", sizeof(net_nis_domain), size); memcpy(&net_nis_domain, ext + 2, size); net_nis_domain[size] = 0; } break; #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) case 42: /* NTP server IP */ net_copy_ip(&net_ntp_server, (struct in_addr *)(ext + 2)); break; #endif /* Application layer fields */ case 43: /* Vendor specific info - Not yet supported */ /* * Binary information to exchange specific * product information. */ break; /* Reserved (custom) fields (128..254) */ } }
void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) { struct arp_hdr *arp; struct in_addr reply_ip_addr; uchar *pkt; int eth_hdr_size; /* * We have to deal with two types of ARP packets: * - REQUEST packets will be answered by sending our * IP address - if we know it. * - REPLY packates are expected only after we asked * for the TFTP server's or the gateway's ethernet * address; so if we receive such a packet, we set * the server ethernet address */ debug_cond(DEBUG_NET_PKT, "Got ARP\n"); arp = (struct arp_hdr *)ip; if (len < ARP_HDR_SIZE) { printf("bad length %d < %d\n", len, ARP_HDR_SIZE); return; } if (ntohs(arp->ar_hrd) != ARP_ETHER) return; if (ntohs(arp->ar_pro) != PROT_IP) return; if (arp->ar_hln != ARP_HLEN) return; if (arp->ar_pln != ARP_PLEN) return; if (net_ip.s_addr == 0) return; if (net_read_ip(&arp->ar_tpa).s_addr != net_ip.s_addr) return; switch (ntohs(arp->ar_op)) { case ARPOP_REQUEST: /* reply with our IP address */ debug_cond(DEBUG_DEV_PKT, "Got ARP REQUEST, return our IP\n"); pkt = (uchar *)et; eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP); pkt += eth_hdr_size; arp->ar_op = htons(ARPOP_REPLY); memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN); net_copy_ip(&arp->ar_tpa, &arp->ar_spa); memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN); net_copy_ip(&arp->ar_spa, &net_ip); #ifdef CONFIG_CMD_LINK_LOCAL /* * Work-around for brain-damaged Cisco equipment with * arp-proxy enabled. * * If the requesting IP is not on our subnet, wait 5ms to * reply to ARP request so that our reply will overwrite * the arp-proxy's instead of the other way around. */ if ((net_read_ip(&arp->ar_tpa).s_addr & net_netmask.s_addr) != (net_read_ip(&arp->ar_spa).s_addr & net_netmask.s_addr)) udelay(5000); #endif net_send_packet((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); return; case ARPOP_REPLY: /* arp reply */ /* are we waiting for a reply */ if (!net_arp_wait_packet_ip.s_addr) break; #ifdef CONFIG_KEEP_SERVERADDR if (net_server_ip.s_addr == net_arp_wait_packet_ip.s_addr) { char buf[20]; sprintf(buf, "%pM", &arp->ar_sha); setenv("serveraddr", buf); } #endif reply_ip_addr = net_read_ip(&arp->ar_spa); /* matched waiting packet's address */ if (reply_ip_addr.s_addr == net_arp_wait_reply_ip.s_addr) { debug_cond(DEBUG_DEV_PKT, "Got ARP REPLY, set eth addr (%pM)\n", arp->ar_data); /* save address for later use */ if (arp_wait_packet_ethaddr != NULL) memcpy(arp_wait_packet_ethaddr, &arp->ar_sha, ARP_HLEN); net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr, 0, len); /* set the mac address in the waiting packet's header and transmit it */ memcpy(((struct ethernet_hdr *)net_tx_packet)->et_dest, &arp->ar_sha, ARP_HLEN); net_send_packet(net_tx_packet, arp_wait_tx_packet_size); /* no arp request pending now */ net_arp_wait_packet_ip.s_addr = 0; arp_wait_tx_packet_size = 0; arp_wait_packet_ethaddr = NULL; } return; default: debug("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op)); return; } }