void arp_raw_request(struct in_addr source_ip, const uchar *target_ethaddr, struct in_addr target_ip) { uchar *pkt; struct arp_hdr *arp; int eth_hdr_size; debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", arp_wait_try); pkt = arp_tx_packet; eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_ARP); pkt += eth_hdr_size; arp = (struct arp_hdr *)pkt; arp->ar_hrd = htons(ARP_ETHER); arp->ar_pro = htons(PROT_IP); arp->ar_hln = ARP_HLEN; arp->ar_pln = ARP_PLEN; arp->ar_op = htons(ARPOP_REQUEST); memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN); /* source ET addr */ net_write_ip(&arp->ar_spa, source_ip); /* source IP addr */ memcpy(&arp->ar_tha, target_ethaddr, ARP_HLEN); /* target ET addr */ net_write_ip(&arp->ar_tpa, target_ip); /* target IP addr */ net_send_packet(arp_tx_packet, eth_hdr_size + ARP_HDR_SIZE); }
static int sb_eth_raw_recv(struct udevice *dev, int flags, uchar **packetp) { struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); int retval = 0; int length; if (reply_arp) { struct arp_hdr *arp = (void *)net_rx_packets[0] + ETHER_HDR_SIZE; /* * Fake an ARP response. The u-boot network stack is sending an * ARP request (to find the MAC address to address the actual * packet to) and requires an ARP response to continue. Since * this is the localhost interface, there is no Etherent level * traffic at all, so there is no way to send an ARP request or * to get a response. For this reason we fake the response to * make the u-boot network stack happy. */ arp->ar_hrd = htons(ARP_ETHER); arp->ar_pro = htons(PROT_IP); arp->ar_hln = ARP_HLEN; arp->ar_pln = ARP_PLEN; arp->ar_op = htons(ARPOP_REPLY); /* Any non-zero MAC address will work */ memset(&arp->ar_sha, 0x01, ARP_HLEN); /* Use whatever IP we were looking for (always 127.0.0.1?) */ net_write_ip(&arp->ar_spa, arp_ip); memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN); net_write_ip(&arp->ar_tpa, net_ip); length = ARP_HDR_SIZE; } else { /* If local, the Ethernet header won't be included; skip it */ uchar *pktptr = priv->local ? net_rx_packets[0] + ETHER_HDR_SIZE : net_rx_packets[0]; retval = sandbox_eth_raw_os_recv(pktptr, &length, priv); } if (!retval && length) { if (priv->local) { struct ethernet_hdr *eth = (void *)net_rx_packets[0]; /* Fill in enough of the missing Ethernet header */ memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN); memset(eth->et_src, 0x01, ARP_HLEN); eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP); reply_arp = 0; length += ETHER_HDR_SIZE; } debug("eth_sandbox_raw: received packet %d\n", length); *packetp = net_rx_packets[0]; return length; } return retval; }
static int bootp_request(void) { struct bootp *bp; int ext_len; int ret; unsigned char *payload = net_udp_get_payload(dhcp_con); const char *bfile; dhcp_state = INIT; debug("BOOTP broadcast\n"); bp = (struct bootp *)payload; bp->bp_op = OP_BOOTREQUEST; bp->bp_htype = HWT_ETHER; bp->bp_hlen = HWL_ETHER; bp->bp_hops = 0; bp->bp_secs = htons(get_time_ns() >> 30); net_write_ip(&bp->bp_ciaddr, 0); net_write_ip(&bp->bp_yiaddr, 0); net_write_ip(&bp->bp_siaddr, 0); net_write_ip(&bp->bp_giaddr, 0); memcpy(bp->bp_chaddr, dhcp_con->et->et_src, 6); bfile = getenv("bootfile"); if (bfile) safe_strncpy (bp->bp_file, bfile, sizeof(bp->bp_file)); /* Request additional information from the BOOTP/DHCP server */ ext_len = dhcp_extended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0); Bootp_id = (uint32_t)get_time_ns(); net_copy_uint32(&bp->bp_id, &Bootp_id); dhcp_state = SELECTING; ret = net_udp_send(dhcp_con, sizeof(*bp) + ext_len); return ret; }
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 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; }