void NetReceive(volatile uchar * inpkt, int len)

来源:互联网 发布:淘宝网有没有海外版 编辑:程序博客网 时间:2024/04/30 20:10
void
NetReceive(volatile uchar * inpkt, int len)
{
    Ethernet_t *et;
    IP_t    *ip;
    ARP_t    *arp;
    IPaddr_t tmp;
    int    x;
    uchar *pkt;
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
    int iscdp;
#endif
    ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;

#ifdef ET_DEBUG
    printf("packet received\n");
#endif

    NetRxPkt = inpkt;
    NetRxPktLen = len;
    et = (Ethernet_t *)inpkt;

    /* too small packet? */
    if (len < ETHER_HDR_SIZE)
        return;

#if (CONFIG_COMMANDS & CFG_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;

    x = ntohs(et->et_protlen);

#ifdef ET_DEBUG
    printf("packet received\n");
#endif

    if (x < 1514) {                                                                    //判断协议
        /*
         *    Got a 802 packet.  Check the other protocol field.
         */
        x = ntohs(et->et_prot);

        ip = (IP_t *)(inpkt + E802_HDR_SIZE);
        len -= E802_HDR_SIZE;

    } else if (x != PROT_VLAN) {    /* normal packet */          //不使用虚拟网
        ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
        len -= ETHER_HDR_SIZE;

    } else {            /* VLAN packet */
        VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;

#ifdef ET_DEBUG
        printf("VLAN packet received\n");
#endif
        /* too small packet? */
        if (len < VLAN_ETHER_HDR_SIZE)
            return;

        /* if no VLAN active */
        if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
#if (CONFIG_COMMANDS & CFG_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;
    }

#ifdef ET_DEBUG
    printf("Receive from protocol 0x%x\n", x);
#endif

#if (CONFIG_COMMANDS & CFG_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:                                               //---------------使用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
         */
#ifdef ET_DEBUG
        puts ("Got ARP\n");
#endif
        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) {           //硬件地址类型
            return;
        }
        if (ntohs(arp->ar_pro) != PROT_IP) {                 //协议
            return;
        }
        if (arp->ar_hln != 6) {                                         //硬件地址长度
            return;
        }
        if (arp->ar_pln != 4) {                                         //ip地址长度
            return;
        }

        if (NetOurIP == 0) {                                             //本地ip
            return;
        }

        if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {        //是否是发给本机的
            return;
        }

        switch (ntohs(arp->ar_op)) {                              //--------------------------判断操作类型
        case ARPOP_REQUEST:        /* reply with our IP address    */
#ifdef ET_DEBUG
            puts ("Got ARP REQUEST, return our IP\n");
#endif
            pkt = (uchar *)et;
            pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
            arp->ar_op = htons(ARPOP_REPLY);
            memcpy   (&arp->ar_data[10], &arp->ar_data[0], 6);
            NetCopyIP(&arp->ar_data[16], &arp->ar_data[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);
            return;

        case ARPOP_REPLY:        /* arp reply */
            /* are we waiting for a reply */
            if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)                     //等待的目标ip和目标mac指针
                break;
#ifdef ET_DEBUG
            printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
                arp->ar_data[0], arp->ar_data[1],
                arp->ar_data[2], arp->ar_data[3],
                arp->ar_data[4], arp->ar_data[5]);
#endif

            tmp = NetReadIP(&arp->ar_data[6]);                                           //读ip

            /* matched waiting packet's address */
            if (tmp == NetArpWaitReplyIP) {                                                  //等待返回地址
#ifdef ET_DEBUG
                puts ("Got it\n");
#endif
                /* save address for later use */
                memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);        //保存mac地址

#ifdef CONFIG_NETCONSOLE
                (*packetHandler)(0,0,0,0);
#endif
                /* modify header, and transmit it */
                memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);         //保存到数据报
                (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);        //发送ICMP请求

                /* no arp request pending now */
                NetArpWaitPacketIP = 0;
                NetArpWaitTxPacketSize = 0;
                NetArpWaitPacketMAC = NULL;

            }
            return;
        default:
#ifdef ET_DEBUG
            printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
#endif
            return;
        }
        break;

    case PROT_RARP:
#ifdef ET_DEBUG
        puts ("Got RARP\n");
#endif
        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");
        } else {
            NetCopyIP(&NetOurIP,    &arp->ar_data[16]);
            if (NetServerIP == 0)
                NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
            memcpy (NetServerEther, &arp->ar_data[ 0], 6);

            (*packetHandler)(0,0,0,0);
        }
        break;

    case PROT_IP:                                                            //----------------使用IP
#ifdef ET_DEBUG
        puts ("Got IP\n");
#endif
        if (len < IP_HDR_SIZE) {
            debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
            return;
        }
        if (len < ntohs(ip->ip_len)) {
            printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
            return;
        }
        len = ntohs(ip->ip_len);
#ifdef ET_DEBUG
        printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
#endif
        if ((ip->ip_hl_v & 0xf0) != 0x40) {
            return;
        }
        if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
            return;
        }
        if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
            puts ("checksum bad\n");
            return;
        }
        tmp = NetReadIP(&ip->ip_dst);
        if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
            return;
        }
        /*
         * watch for ICMP host redirects
         *
         * 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.
         */
        if (ip->ip_p == IPPROTO_ICMP) {                              //-----------------ICMP
            ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);

            switch (icmph->type) {
            case ICMP_REDIRECT:
                if (icmph->code != ICMP_REDIR_HOST)
                    return;
                puts (" ICMP Host Redirect to ");
                print_IPaddr(icmph->un.gateway);
                putc(' ');
                return;
#if (CONFIG_COMMANDS & CFG_CMD_PING)
            case ICMP_ECHO_REPLY:
                /*
                 *    IP header OK.  Pass the packet to the current handler.
                 */
                /* XXX point to ip packet */
                (*packetHandler)((uchar *)ip, 0, 0, 0);
                return;
#endif
            default:
                return;
            }
        } else if (ip->ip_p != IPPROTO_UDP) {    /* Only UDP packets */
            return;
        }

#ifdef CONFIG_UDP_CHECKSUM
        if (ip->udp_xsum != 0) {
            ulong   xsum;
            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) {
                ushort sumdata;

                sumdata = *sumptr++;
                xsum += ntohs(sumdata);
                sumlen -= 2;
            }
            if (sumlen > 0) {
                ushort sumdata;

                sumdata = *(unsigned char *) sumptr;
                sumdata = (sumdata << 8) & 0xff00;
                xsum += sumdata;
            }
            while ((xsum >> 16) != 0) {
                xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
            }
            if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
                printf(" UDP wrong checksum %08x %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_dst),
                        ntohs(ip->udp_src),
                        ntohs(ip->udp_len) - 8);
        break;
    }
}
原创粉丝点击