/* @@@ 2003-10-24: modified by OS for udp packet queue */
void NutUdpInput(NETBUF * nb, ureg_t bcast)
{
    UDPHDR *uh;
    UDPSOCKET *sock;

    uh = (UDPHDR *) nb->nb_tp.vp;

    nb->nb_ap.vp = uh + 1;
    nb->nb_ap.sz = nb->nb_tp.sz - sizeof(UDPHDR);
    nb->nb_tp.sz = sizeof(UDPHDR);

    /*
     * Find a port. If none exists and if this datagram hasn't been
     * broadcasted, return an ICMP unreachable.
     */
    if ((sock = NutUdpFindSocket(uh->uh_dport)) == 0) {
        if (bcast || NutIcmpResponse(ICMP_UNREACH, ICMP_UNREACH_PORT, 0, nb) == 0) {
        	NutNetBufFree(nb);
        }
        return;
    }

    /* if buffer size is defined, use packet queue */
    if (sock->so_rx_bsz) {
        /* New packet fits into the buffer? */
        if (sock->so_rx_cnt + nb->nb_ap.sz > sock->so_rx_bsz) {
            /* No, so discard it */
            NutNetBufFree(nb);
            return;
        } else {
            /* if a first packet is already in the queue, find the end
             * and add the new packet */
            if (sock->so_rx_nb) {
                NETBUF *snb;
                for (snb = sock->so_rx_nb; snb->nb_next != 0; snb = snb->nb_next);
                snb->nb_next = nb;
            } else
                sock->so_rx_nb = nb;

            /* increment input buffer count */
            sock->so_rx_cnt += nb->nb_ap.sz;
        };
    } else {                    /* no packet queue */
        /* if a packet is still buffered, discard it */
        if (sock->so_rx_nb) {
            NutNetBufFree(sock->so_rx_nb);
        }
        sock->so_rx_nb = nb;
        sock->so_rx_cnt = nb->nb_ap.sz; /* set input buffer count to size of new packet */
    };

    /* post the event only, if one thread is waiting */
    if (sock->so_rx_rdy)
        NutEventPost(&sock->so_rx_rdy);
}
Esempio n. 2
0
/*!
 * \brief Process incoming IP datagrams.
 * \internal
 *
 * Datagrams addressed to other destinations and datagrams
 * whose version number is not 4 are silently discarded.
 *
 * This routine is called by the Ethernet layer on incoming IP datagrams.
 *
 * \param dev Identifies the device that received this datagram.
 * \param nb  The network buffer received.
 */
void NutIpInput(NUTDEVICE * dev, NETBUF * nb)
{
    IPHDR *ip;
    uint_fast8_t hdrlen;
    uint32_t dst;
    uint_fast8_t bcast = 0;
    IFNET *nif;

    ip = nb->nb_nw.vp;

    /*
     * Silently discard datagrams of different IP version as well as
     * fragmented or filtered datagrams.
     */
    if (ip->ip_v != IPVERSION ||        /* Version check. */
        (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) != 0 ||      /* Fragmentation. */
        (NutIpFilter && NutIpFilter(ip->ip_src))) {     /* Filter. */
        NutNetBufFree(nb);
        return;
    }

    /*
    ** IP header length is given in 32-bit fields. Calculate the size in
    ** bytes and make sure that the header we know will fit in. Check
    ** further, that the header length is not larger than the bytes we
    ** received.
    */
    hdrlen = ip->ip_hl * 4;
    if (hdrlen < sizeof(IPHDR) || hdrlen > nb->nb_nw.sz) {
        NutNetBufFree(nb);
        return;
    }

#if NUT_IP_INCHKSUM
    /* Optional checksum calculation on incoming datagrams. */
#endif

    dst = ip->ip_dst;
    nif = dev->dev_icb;

    /*
     * Check for limited broadcast.
     */
    if (dst == INADDR_BROADCAST) {
        bcast = 1;
    }

    /*
     * Check for multicast.
     */
    else if (IN_MULTICAST(dst)) {
        MCASTENTRY *mca;

        for (mca = nif->if_mcast; mca; mca = mca->mca_next) {
            if (dst == mca->mca_ip) {
                break;
            }
        }
        if (mca == NULL) {
            NutNetBufFree(nb);
            return;
        }
        bcast = 2;
    }

    /*
     * Check device's local IP address.
     */
    else if (nif->if_local_ip != 0) {
        /*
         * Check for unicast.
         */
        if (dst == nif->if_local_ip) {
            nb->nb_flags |= NBAF_UNICAST;
        }

        /*
         * Check for net-directed broadcast.
         */
        else if (~nif->if_mask && (dst & ~nif->if_mask) == ~nif->if_mask) {
            bcast = 1;
        }

        /*
         * Not for us, discard silently.
         */
        else {
            NutIpForward(nb);
            NutNetBufFree(nb);
            return;
        }
    }

    /*
     * Calculate IP data length.
     */
    nb->nb_tp.sz = htons(ip->ip_len);
    if (nb->nb_tp.sz < hdrlen || nb->nb_tp.sz > nb->nb_nw.sz) {
        NutNetBufFree(nb);
        return;
    }
    nb->nb_nw.sz = hdrlen;
    nb->nb_tp.sz -= hdrlen;
    if (nb->nb_tp.sz) {
        nb->nb_tp.vp = ((char *) ip) + hdrlen;
    }

    /*
     * Route valid datagram to the related handler.
     */
    if (ip_demux == NULL || (*ip_demux) (dev, nb)) {
        switch (ip->ip_p) {
        case IPPROTO_ICMP:
            NutIcmpInput(dev, nb);
            break;
        case IPPROTO_IGMP:
            NutIgmpInput(dev, nb);
            break;
        default:
            /* Unknown protocol, send ICMP destination (protocol)
            * unreachable message.
            */
            if (bcast || !NutIcmpResponse(ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, nb))
                NutNetBufFree(nb);
            break;
        }
    }
}