Newer
Older
return ip; /* not a fragment */
return NULL;
}
#endif
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
/**
* Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
* drop others.
*
* @parma ip IP packet containing the ICMP
*/
static void receive_icmp(IP_t *ip, int len, IPaddr_t src_ip, Ethernet_t *et)
{
ICMP_t *icmph = (ICMP_t *)&ip->udp_src;
switch (icmph->type) {
case ICMP_REDIRECT:
if (icmph->code != ICMP_REDIR_HOST)
return;
printf(" ICMP Host Redirect to %pI4 ",
&icmph->un.gateway);
break;
#if defined(CONFIG_CMD_PING)
case ICMP_ECHO_REPLY:
/*
* IP header OK. Pass the packet to the
* current handler.
*/
/*
* XXX point to ip packet - should this use
* packet_icmp_handler?
*/
(*packetHandler)((uchar *)ip, 0, src_ip, 0, 0);
break;
case ICMP_ECHO_REQUEST:
debug("Got ICMP ECHO REQUEST, return %d bytes\n",
ETHER_HDR_SIZE + len);
memcpy(&et->et_dest[0], &et->et_src[0], 6);
memcpy(&et->et_src[0], NetOurEther, 6);
ip->ip_sum = 0;
ip->ip_off = 0;
NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
NetCopyIP((void *)&ip->ip_src, &NetOurIP);
ip->ip_sum = ~NetCksum((uchar *)ip,
IP_HDR_SIZE_NO_UDP >> 1);
icmph->type = ICMP_ECHO_REPLY;
icmph->checksum = 0;
icmph->checksum = ~NetCksum((uchar *)icmph,
(len - IP_HDR_SIZE_NO_UDP) >> 1);
(void) eth_send((uchar *)et,
ETHER_HDR_SIZE + len);
break;
#endif
default:
if (packet_icmp_handler)
packet_icmp_handler(icmph->type, icmph->code,
ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
icmph->un.data, ntohs(ip->udp_len));
break;
}
}
{
Ethernet_t *et;
IP_t *ip;
ARP_t *arp;
IPaddr_t tmp;
#if defined(CONFIG_CMD_CDP)
int iscdp;
#endif
ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
NetRxPacket = inpkt;
NetRxPacketLen = len;
et = (Ethernet_t *)inpkt;
/* too small packet? */
if (len < ETHER_HDR_SIZE)
return;
#ifdef CONFIG_API
if (push_packet) {
(*push_packet)(inpkt, len);
return;
}
#endif
#if defined(CONFIG_CMD_CDP)
/* keep track if packet is CDP */
iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
#endif
myvlanid = ntohs(NetOurVLAN);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
mynvlanid = ntohs(NetOurNativeVLAN);
if (mynvlanid == (ushort)-1)
mynvlanid = VLAN_NONE;
if (x < 1514) {
/*
* Got a 802 packet. Check the other protocol field.
*/
x = ntohs(et->et_prot);
ip = (IP_t *)(inpkt + E802_HDR_SIZE);
} else if (x != PROT_VLAN) { /* normal packet */
ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
} else { /* VLAN packet */
VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
/* too small packet? */
if (len < VLAN_ETHER_HDR_SIZE)
return;
/* if no VLAN active */
if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
#if defined(CONFIG_CMD_CDP)
&& iscdp == 0
#endif
)
return;
cti = ntohs(vet->vet_tag);
vlanid = cti & VLAN_IDMASK;
x = ntohs(vet->vet_type);
ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
len -= VLAN_ETHER_HDR_SIZE;
#if defined(CONFIG_CMD_CDP)
if (iscdp) {
CDPHandler((uchar *)ip, len);
return;
}
#endif
if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
if (vlanid == VLAN_NONE)
vlanid = (mynvlanid & VLAN_IDMASK);
/* not matched? */
if (vlanid != (myvlanid & VLAN_IDMASK))
return;
}
switch (x) {
case PROT_ARP:
/*
* 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
arp = (ARP_t *)ip;
if (len < ARP_HDR_SIZE) {
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
if (ntohs(arp->ar_hrd) != ARP_ETHER)
if (ntohs(arp->ar_pro) != PROT_IP)
if (NetReadIP(&arp->ar_data[16]) != NetOurIP)
case ARPOP_REQUEST:
/* reply with our IP address */
pkt = (uchar *)et;
pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
memcpy(&arp->ar_data[10], &arp->ar_data[0], 6);
memcpy(&arp->ar_data[0], NetOurEther, 6);
NetCopyIP(&arp->ar_data[6], &NetOurIP);
(void) eth_send((uchar *)et,
(pkt - (uchar *)et) + ARP_HDR_SIZE);
case ARPOP_REPLY: /* arp reply */
/* are we waiting for a reply */
if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
break;
#ifdef CONFIG_KEEP_SERVERADDR
if (NetServerIP == NetArpWaitPacketIP) {
char buf[20];
sprintf(buf, "%pM", arp->ar_data);
setenv("serveraddr", buf);
}
#endif
debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
arp->ar_data);
tmp = NetReadIP(&arp->ar_data[6]);
/* matched waiting packet's address */
if (tmp == NetArpWaitReplyIP) {
memcpy(NetArpWaitPacketMAC,
&arp->ar_data[0], 6);
#ifdef CONFIG_NETCONSOLE
(*packetHandler)(0, 0, 0, 0, 0);
memcpy(((Ethernet_t *)NetArpWaitTxPacket)->
et_dest, NetArpWaitPacketMAC, 6);
(void) eth_send(NetArpWaitTxPacket,
NetArpWaitTxPacketSize);
/* no arp request pending now */
NetArpWaitPacketIP = 0;
NetArpWaitTxPacketSize = 0;
NetArpWaitPacketMAC = NULL;
}
debug("Unexpected ARP opcode 0x%x\n",
ntohs(arp->ar_op));
arp = (ARP_t *)ip;
if (len < ARP_HDR_SIZE) {
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
(ntohs(arp->ar_hrd) != ARP_ETHER) ||
(ntohs(arp->ar_pro) != PROT_IP) ||
(arp->ar_hln != 6) || (arp->ar_pln != 4)) {
puts("invalid RARP header\n");
NetCopyIP(&NetOurIP, &arp->ar_data[16]);
NetCopyIP(&NetServerIP, &arp->ar_data[6]);
memcpy(NetServerEther, &arp->ar_data[0], 6);
(*packetHandler)(0, 0, 0, 0, 0);
/* Before we start poking the header, make sure it is there */
debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
if (len < ntohs(ip->ip_len)) {
printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
return;
}
len = ntohs(ip->ip_len);
debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
/* Can't deal with anything except IPv4 */
if ((ip->ip_hl_v & 0xf0) != 0x40)
/* Can't deal with IP options (headers != 20 bytes) */
if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
tmp = NetReadIP(&ip->ip_dst);
if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
/* Read source IP address for later use */
src_ip = NetReadIP(&ip->ip_src);
/*
* The function returns the unchanged packet if it's not
* a fragment, and either the complete packet or NULL if
* it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
*/
ip = NetDefragment(ip, &len);
if (!ip)
* There is no real handler code (yet). We just watch
* for ICMP host redirect messages. In case anybody
* sees these messages: please contact me
* (wd@denx.de), or - even better - send me the
* necessary fixes :-)
* Note: in all cases where I have seen this so far
* it was a problem with the router configuration,
* for instance when a router was configured in the
* BOOTP reply, but the TFTP server was on the same
* subnet. So this is probably a warning that your
* configuration might be wrong. But I'm not really
* sure if there aren't any other situations.
*
* Simon Glass <sjg@chromium.org>: We get an ICMP when
* we send a tftp packet to a dead connection, or when
* there is no server at the other end.
receive_icmp(ip, len, src_ip, et);
return;
} else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
return;
}
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ushort *sumptr;
ushort sumlen;
xsum = ip->ip_p;
xsum += (ntohs(ip->udp_len));
xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_src) >> 0) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst) >> 0) & 0x0000ffff;
sumlen = ntohs(ip->udp_len);
sumptr = (ushort *) &(ip->udp_src);
while (sumlen > 1) {
sumdata = *sumptr++;
xsum += ntohs(sumdata);
sumlen -= 2;
}
if (sumlen > 0) {
sumdata = *(unsigned char *) sumptr;
xsum += sumdata;
}
while ((xsum >> 16) != 0) {
xsum = (xsum & 0x0000ffff) +
((xsum >> 16) & 0x0000ffff);
}
if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
printf(" UDP wrong checksum %08lx %08x\n",
xsum, ntohs(ip->udp_xsum));
return;
}
}
#endif
#ifdef CONFIG_NETCONSOLE
nc_input_packet((uchar *)ip + IP_HDR_SIZE,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);
#endif
/*
* IP header OK. Pass the packet to the current handler.
*/
(*packetHandler)((uchar *)ip + IP_HDR_SIZE,
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);
break;
}
}
/**********************************************************************/
static int net_check_prereq(enum proto_t protocol)
#if defined(CONFIG_CMD_PING)
puts("*** ERROR: ping address not given\n");
#if defined(CONFIG_CMD_SNTP)
case SNTP:
if (NetNtpServerIP == 0) {
puts("*** ERROR: NTP server address not given\n");
#if defined(CONFIG_CMD_DNS)
case DNS:
if (NetOurDNSIP == 0) {
puts("*** ERROR: DNS server address not given\n");
return 1;
}
goto common;
#endif
#if defined(CONFIG_CMD_NFS)
puts("*** ERROR: `serverip' not set\n");
#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
defined(CONFIG_CMD_DNS)
common:
puts("*** ERROR: `ipaddr' not set\n");
if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
int num = eth_get_dev_index();
puts("*** ERROR: No ethernet found.\n");
puts("*** ERROR: `ethaddr' not set\n");
printf("*** ERROR: `eth%daddr' not set\n",
return 0; /* OK */
}
/**********************************************************************/
int
NetCksumOk(uchar *ptr, int len)
{
return !((NetCksum(ptr, len) + 1) & 0xfffe);
}
unsigned
NetCksum(uchar *ptr, int len)
ushort *p = (ushort *)ptr;
xsum = (xsum & 0xffff) + (xsum >> 16);
xsum = (xsum & 0xffff) + (xsum >> 16);
return xsum & 0xffff;
int
NetEthHdrSize(void)
{
ushort myvlanid;
myvlanid = ntohs(NetOurVLAN);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
VLAN_ETHER_HDR_SIZE;
NetSetEther(uchar *xet, uchar * addr, uint prot)
ushort myvlanid;
myvlanid = ntohs(NetOurVLAN);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
memcpy(et->et_dest, addr, 6);
memcpy(et->et_src, NetOurEther, 6);
if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
return ETHER_HDR_SIZE;
} else {
VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
vet->vet_vlan_type = htons(PROT_VLAN);
vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
vet->vet_type = htons(prot);
return VLAN_ETHER_HDR_SIZE;
}
}
NetSetIP(uchar *xip, IPaddr_t dest, int dport, int sport, int len)
/*
* If the data is an odd number of bytes, zero the
* byte after the last byte so that the checksum
* will work.
*/
if (len & 1)
xip[IP_HDR_SIZE + len] = 0;
/*
* Construct an IP and UDP header.
/* IP_HDR_SIZE / 4 (not including UDP) */
ip->ip_hl_v = 0x45;
ip->ip_tos = 0;
ip->ip_len = htons(IP_HDR_SIZE + len);
ip->ip_id = htons(NetIPID++);
ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
ip->ip_ttl = 255;
ip->ip_p = 17; /* UDP */
ip->ip_sum = 0;
/* already in network byte order */
NetCopyIP((void *)&ip->ip_src, &NetOurIP);
NetCopyIP((void *)&ip->ip_dst, &dest);
ip->udp_src = htons(sport);
ip->udp_dst = htons(dport);
ip->udp_len = htons(8 + len);
ip->udp_xsum = 0;
ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
}
void copy_filename(char *dst, const char *src, int size)
{
if (*src && (*src == '"')) {
++src;
--size;
}
while ((--size > 0) && *src && (*src != '"'))
#if defined(CONFIG_CMD_NFS) || \
defined(CONFIG_CMD_SNTP) || \
defined(CONFIG_CMD_DNS)
* make port a little random (1024-17407)
* This keeps the math somewhat trivial to compute, and seems to work with
* all supported protocols/clients/servers
return 1024 + (get_timer(0) % 0x4000);
void ip_to_string(IPaddr_t x, char *s)
x = ntohl(x);
sprintf(s, "%d.%d.%d.%d",
(int) ((x >> 24) & 0xff),
(int) ((x >> 16) & 0xff),
(int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
void VLAN_to_string(ushort x, char *s)
{
x = ntohs(x);
if (x == (ushort)-1)
x = VLAN_NONE;
if (x == VLAN_NONE)
strcpy(s, "none");
else
sprintf(s, "%d", x & VLAN_IDMASK);
}
ushort string_to_VLAN(const char *s)
{
ushort id;
if (s == NULL)
if (*s < '0' || *s > '9')
id = VLAN_NONE;
else
id = (ushort)simple_strtoul(s, NULL, 10);
}
ushort getenv_VLAN(char *var)
{
return string_to_VLAN(getenv(var));