/* @@@ 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); }
/*! * \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; } } }