📄 net_ipv4.c
字号:
/***************************************** Copyright (c) 2002-2004 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This file is part of the boot loader *//* * net_ipv4.c * * UDP/IP protocol implementation * * by Ho Lee 11/18/2002 */#include "config.h"#include "util.h"#include "vsprintf.h"#include "uart.h"#include "timer.h"#include "net.h"#include "net_ipv4.h"#if 0#define DPRINTF(x...) uart_printf(x)#else#define DPRINTF(x...)#endif//// global variables//// ethernet static unsigned char g_eth_broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };// ARParptable_t g_arptable[MAX_ARPTABLE];//// Init// int ipv4_init(void){ return 0;}void ipv4_setup_arptable(in_addr_t ipaddr, in_addr_t netmask, unsigned char *node, in_addr_t gateway, in_addr_t dns){ arp_setaddr_index(ARP_CLIENT, ipaddr, netmask, node); arp_setaddr_index(ARP_GATEWAY, gateway, INADDR_ANY, NULL); arp_setaddr_index(ARP_DNS, dns, INADDR_ANY, NULL);}//// TCP/IP Basic//// return // 0 : A class// 1 : B class// 2 : C class// < 0 : invalidint ipv4_get_ipaddr_class(in_addr_t ipaddr){ if (IN_CLASSA(ipaddr)) return 0; else if (IN_CLASSB(ipaddr)) return 1; else if (IN_CLASSC(ipaddr)) return 2; else return -1;}// check IP address class and return appropriate default network mask address// return INADDR_INVALID if the address is not validin_addr_t ipv4_get_default_netmask(in_addr_t ipaddr){ switch (ipv4_get_ipaddr_class(ipaddr)) { case 0 : return IN_CLASSA_NET; case 1 : return IN_CLASSB_NET; case 2 : return IN_CLASSC_NET; default : return INADDR_INVALID; }}// check if the IP address is valid// IP address should not be zero or broadcast address in the subclassint ipv4_ipaddr_valid(in_addr_t ipaddr){ int netmask; // zero of broadcast if (ipaddr == INADDR_ANY || ipaddr == INADDR_BROADCAST) return 0; // check if the address is in the valid region if (ipv4_get_ipaddr_class(ipaddr) < 0) return 0; // check if the address is zero or broadcast in the subclass netmask = ipv4_get_default_netmask(ipaddr); ipaddr &= ~netmask; if (ipaddr == 0 || ipaddr == (~netmask)) return 0; return 1;}// assign not assigned user portint ipv4_alloc_port(void){ static int s_lastport = IPPORT_RESERVED; if (++s_lastport == IPPORT_USERRESERVED) s_lastport = IPPORT_RESERVED; return s_lastport;}//// Packet processing//// decide whether to accept the packet or discard it. // called before decapsulating the packetint ipv4_check_for_me(struct sk_buff *skb){ DPRINTF("RX : %d, To = %02x:%02x:%02x:%02x:%02x:%02x, From = %02x:%02x:%02x:%02x:%02x:%02x, Proto = %02x%02x\n", skb->len, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5], skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11], skb->data[12], skb->data[13] ); // if the destination is my MAC address, it's for me if (memcmp(skb->data, g_arptable[ARP_CLIENT].node, ETH_ALEN) == 0) return 1; // accept just a few of broadcast message // 1. BOOTP/DHCP response // 2. ARP request if (memcmp(skb->data, g_eth_broadcast, ETH_ALEN) == 0) { struct ethhdr *eth; struct iphdr *ip; struct udphdr *udp; struct arprequest *arp; eth = (struct ethhdr *) skb->data; switch (ntohs(eth->h_proto)) { case ETH_P_IP : ip = (struct iphdr *) (skb->data + sizeof(struct ethhdr)); switch (ip->protocol) { case IPPROTO_UDP : udp = (struct udphdr *) (skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr)); if (ntohs(udp->dest) == IPPORT_BOOTP_CLIENT) return 1; break; } break; case ETH_P_ARP : arp = (struct arprequest *) (skb->data + sizeof(struct ethhdr)); // uart_printf("ARP for %d, %s\n", ntohs(arp->ar_op), ipaddr_to_str(ntohl(arp->ar_tip))); if (ntohl(arp->ar_tip) == g_arptable[ARP_CLIENT].ipaddr) return 1; break; } } return 0;}// parse the ethernet packet// fix the byte orderint ipv4_parsepacket(struct sk_buff *skb){ int len = skb->len; // parse ethernet header skb->eth = (struct ethhdr *) skb->data; skb->eth->h_proto = ntohs(skb->eth->h_proto); skb->ethdata = skb->data + ETH_HLEN; len -= ETH_HLEN; skb->ethdata_len = len; // parse ethernet data skb->arp = NULL; skb->ip = NULL; skb->ipdata = NULL; skb->icmp = NULL; skb->udp = NULL; skb->udpdata = NULL; skb->bootp = NULL; skb->tftp = NULL; // parse each protocol header (especially byte order) switch (skb->eth->h_proto) { case ETH_P_IP : DPRINTF("IP : "); skb->ip = (struct iphdr *) skb->ethdata; if (ipv4_calc_checksum(skb->ip, sizeof(struct iphdr)) != 0) { uart_puts("IP packet checksum error.\n"); return 1; } skb->ip->tot_len = ntohs(skb->ip->tot_len); skb->ip->id = ntohs(skb->ip->id); skb->ip->frag_off = ntohs(skb->ip->frag_off); skb->ip->saddr = ntohl(skb->ip->saddr); skb->ip->daddr = ntohl(skb->ip->daddr); skb->ipdata = skb->ethdata + sizeof(struct iphdr); if (len < skb->ip->tot_len) { uart_printf("Received IP packet is small. Received = %d, supposed to be %d\n", len, skb->ip->tot_len); return 1; } if (len > skb->ip->tot_len) len = skb->ip->tot_len; len -= sizeof(struct iphdr); skb->ipdata_len = len; switch (skb->ip->protocol) { case IPPROTO_IP : DPRINTF("IP\n"); break; case IPPROTO_ICMP : DPRINTF("ICMP\n"); skb->icmp = (struct icmphdr *) skb->ipdata; if (ipv4_calc_checksum(skb->icmp, len) != 0) { uart_puts("ICMP packet checksum error.\n"); return 1; } if (skb->icmp->type == ICMP_ECHOREPLY || skb->icmp->type == ICMP_ECHO) { skb->icmp->un.echo.id = ntohs(skb->icmp->un.echo.id); skb->icmp->un.echo.sequence = ntohs(skb->icmp->un.echo.sequence); } // ipv4_dump_packet(skb, 0, 0); break; case IPPROTO_UDP : DPRINTF("UDP\n"); skb->udp = (struct udphdr *) skb->ipdata; if (ipv4_calc_tcpudp_checksum(skb->udp, len, skb->ip->saddr, skb->ip->daddr) != 0) { uart_puts("UDP checksum error.\n"); return 1; } skb->udp->src = ntohs(skb->udp->src); skb->udp->dest = ntohs(skb->udp->dest); skb->udp->len = ntohs(skb->udp->len); if (skb->udp->len != len) { uart_puts("UDP packet size mismatch\n"); return 1; } skb->udpdata = skb->ipdata + sizeof(struct udphdr); len -= sizeof(struct udphdr); skb->udpdata_len = len; } break; case ETH_P_ARP : skb->arp = (struct arprequest *) skb->ethdata; skb->arp->ar_hrd = ntohs(skb->arp->ar_hrd); skb->arp->ar_pro = ntohs(skb->arp->ar_pro); skb->arp->ar_op = ntohs(skb->arp->ar_op); skb->arp->ar_sip = ntohl(skb->arp->ar_sip); skb->arp->ar_tip = ntohl(skb->arp->ar_tip); DPRINTF("ARP : %d, from = %s, to = %s\n", skb->arp->ar_op, ipaddr_to_str(skb->arp->ar_sip), ipaddr_to_str(skb->arp->ar_tip)); break; case ETH_P_RARP : DPRINTF("RARP\n"); break; default : return 1; } return 0;}// return // 0 : packet is not processed// 1 : packet is processedint ipv4_processpacket(struct sk_buff *skb){ switch (skb->eth->h_proto) { case ETH_P_IP : if (skb->icmp && skb->icmp->type == ICMP_ECHO) { // reply to echo request int len = skb->ipdata_len; DPRINTF("Received ECHO request\n"); skb->icmp->type = ICMP_ECHOREPLY; skb->icmp->un.echo.id = htons(skb->icmp->un.echo.id); skb->icmp->un.echo.sequence = htons(skb->icmp->un.echo.sequence); skb->icmp->checksum = 0; skb->icmp->checksum = ipv4_calc_checksum(skb->icmp, len); len += sizeof(struct iphdr); // transmit ICMP packet asynchronously ip_transmit(skb->ip->saddr, IPPROTO_ICMP, len, skb->ip, 1); return 1; } break; case ETH_P_ARP : // reply to ARP request if (skb->arp->ar_op == ARPOP_REQUEST) { arptable_t *arp; in_addr_t sipaddr, tipaddr; // Add or update ARP table tipaddr = skb->arp->ar_tip; if (tipaddr == g_arptable[ARP_CLIENT].ipaddr) { sipaddr = skb->arp->ar_sip; if ((arp = arp_lookup(sipaddr)) == NULL) arp = arp_alloc(); if (arp) arp_setaddr(arp, sipaddr, INADDR_ANY, skb->arp->ar_sha); // transmit ARP reply packet DPRINTF("Received ARP request\n"); arp_transmit(ARPOP_REPLY, sipaddr, skb->arp->ar_sha, 1); return 1; } } break; case ETH_P_RARP : break; } return 0;}//// Ethernet//// send ethernet packet to specified ethernet address// dest : ethernet address// type : ethernet protocol ID (ETH_P_xxx)int eth_transmit(unsigned char *dest, uint16_t type, unsigned int len, const void *buf, int async){ struct sk_buff *skb = skb_alloc_tx(len + ETH_HLEN); ethhdr_t *pethhdr = (ethhdr_t *) skb->data; // fill ethernet header memcpy(pethhdr->h_dest, dest, ETH_ALEN); // Destination address memcpy(pethhdr->h_source, g_arptable[ARP_CLIENT].node, ETH_ALEN); // Source address pethhdr->h_proto = htons(type); // Frame type memcpy(skb->data + ETH_HLEN, buf, len); // Frame data // fill sk_buff structure skb->len = len + ETH_HLEN; skb->valid = 1; // send it! return net_sendpacket(skb, async);}struct sk_buff *eth_receive(int type, int timeout){ struct sk_buff *skb; unsigned int startticks = timer_getticks(); if (!em86xx_irqenabled()) { uart_puts("Warning from eth_receive() : interrupt disabled, not able to receive new packet\n"); return NULL; } while ((skb = net_getpacket(timeout)) != NULL) { // ipv4_dump_packet(skb, 0, 0); switch (type) { case WAIT_NOTHING : break; case WAIT_ARP_REPLY : if (skb->arp && skb->arp->ar_op == ARPOP_REPLY) return skb; break; case WAIT_ICMP_REPLY : if (skb->icmp && skb->icmp->type == ICMP_ECHOREPLY) return skb; break; case WAIT_UDP : if (skb->udp) return skb; break; } ipv4_processpacket(skb); skb_free(skb); if (timer_timeout(startticks, timeout)) break; } return NULL;}//// ARP table//arptable_t *arp_lookup(unsigned long ipaddr){ int i; for (i = 0; i < MAX_ARPTABLE; ++i) if (g_arptable[i].ipaddr == ipaddr) return g_arptable + i; return NULL;}arptable_t *arp_alloc(void){ int i; for (i = ARP_USER; i < MAX_ARPTABLE; ++i) if (g_arptable[i].ipaddr == INADDR_ANY) break; if (i == MAX_ARPTABLE) return NULL; return g_arptable + i;}int arp_valid(arptable_t *arp){ int i; if (!ipv4_ipaddr_valid(arp->ipaddr)) return 0; for (i = 0; i < ETH_ALEN; ++i) if (arp->node[i] != 0) return 1; return 0;}void arp_setaddr(arptable_t *arp, in_addr_t ipaddr, in_addr_t netmask, unsigned char *node){ arp->ipaddr = ipaddr; arp->netmask = (netmask == INADDR_ANY) ? ipv4_get_default_netmask(ipaddr) : netmask; if (node) memcpy(arp->node, node, ETH_ALEN); else memset(arp->node, 0, ETH_ALEN);}void arp_setaddr_index(int index, in_addr_t ipaddr, in_addr_t netmask, unsigned char *node){ arp_setaddr(g_arptable + index, ipaddr, netmask, node);}void arp_listtable(arptable_t *arp){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -