ip_input.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,992 行 · 第 1/4 页
C
1,992 行
pass: /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(m)) {#ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL;#endif return; } /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no * matter if it is destined to another node, or whether it is * a multicast one, RSVP wants it! and prevents it from being forwarded * anywhere else. Also checks if the rsvp daemon is running before * grabbing the packet. */ if (rsvp_on && ip->ip_p==IPPROTO_RSVP) goto ours;#ifdef NATPT /* * NATPT (Network Address Translation - Protocol Translation) */ if (ip6_protocol_tr) { struct mbuf *m1 = NULL; switch (natpt_in4(m, &m1)) { case IPPROTO_IP: /* this packet is not changed */ goto checkaddresses; case IPPROTO_IPV4: ip_forward(m1, 0); break; case IPPROTO_IPV6: ip6_forward(m1, 1); break; case IPPROTO_DONE: /* discard without free */ return; case IPPROTO_MAX: /* discard this packet */ default: break; } if (m != m1) m_freem(m); return; }checkaddresses:;#endif /* * Check our list of addresses, to see if the packet is for us. * If we don't have any addresses, assume any unicast packet * we receive might be for us (and let the upper layers deal * with it). */ if (TAILQ_EMPTY(&in_ifaddrhead) && (m->m_flags & (M_MCAST|M_BCAST)) == 0) goto ours; /* * Cache the destination address of the packet; this may be * changed by use of 'ipfw fwd'. */ pkt_dst = ip_fw_fwd_addr == NULL ? ip->ip_dst : ip_fw_fwd_addr->sin_addr; /* * Enable a consistency check between the destination address * and the arrival interface for a unicast packet (the RFC 1122 * strong ES model) if IP forwarding is disabled and the packet * is not locally generated and the packet is not subject to * 'ipfw fwd'. * * XXX - Checking also should be disabled if the destination * address is ipnat'ed to a different interface. * * XXX - Checking is incompatible with IP aliases added * to the loopback interface instead of the interface where * the packets are received. */ checkif = ip_checkinterface && (ipforwarding == 0) && ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && (ip_fw_fwd_addr == NULL); TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {#define satosin(sa) ((struct sockaddr_in *)(sa))#ifdef BOOTP_COMPAT if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) goto ours;#endif /* * If the address matches, verify that the packet * arrived via the correct interface if checking is * enabled. */ if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) goto ours; /* * Only accept broadcast packets that arrive via the * matching interface. Reception of forwarded directed * broadcasts would be handled via ip_forward() and * ether_output() with the loopback into the stack for * SIMPLEX interfaces handled by ether_output(). */ if (ia->ia_ifp == m->m_pkthdr.rcvif && ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == pkt_dst.s_addr) goto ours; if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) goto ours; } } if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { struct in_multi *inm; if (ip_mrouter) { /* * If we are acting as a multicast router, all * incoming multicast packets are passed to the * kernel-level multicast forwarding function. * The packet is returned (relatively) intact; if * ip_mforward() returns a non-zero value, the packet * must be discarded, else it may be accepted below. */ if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { ipstat.ips_cantforward++; m_freem(m); return; } /* * The process-level routing demon needs to receive * all multicast IGMP packets, whether or not this * host belongs to their destination groups. */ if (ip->ip_p == IPPROTO_IGMP) goto ours; ipstat.ips_forward++; } /* * See if we belong to the destination multicast group on the * arrival interface. */ IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); if (inm == NULL) { ipstat.ips_notmember++; m_freem(m); return; } goto ours; } if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) goto ours; if (ip->ip_dst.s_addr == INADDR_ANY) goto ours;#if defined(NFAITH) && 0 < NFAITH /* * FAITH(Firewall Aided Internet Translator) */ if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { if (ip_keepfaith) { if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) goto ours; } m_freem(m); return; }#endif /* * Not for us; forward if possible and desirable. */ if (ipforwarding == 0) { ipstat.ips_cantforward++; m_freem(m); } else ip_forward(m, 0);#ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL;#endif return;ours: /* Count the packet in the ip address stats */ if (ia != NULL) { ia->ia_ifa.if_ipackets++; ia->ia_ifa.if_ibytes += m->m_pkthdr.len; } /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) */ if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) {#if 0 /* * Reassembly should be able to treat a mbuf cluster, for later * operation of contiguous protocol headers on the cluster. (KAME) */ if (m->m_flags & M_EXT) { /* XXX */ if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_toosmall++;#ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL;#endif return; } ip = mtod(m, struct ip *); }#endif /* If maxnipq is 0, never accept fragments. */ if (maxnipq == 0) { ipstat.ips_fragments++; ipstat.ips_fragdropped++; goto bad; } sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); /* * Look for queue of fragments * of this datagram. */ for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; fp = 0; /* * Enforce upper bound on number of fragmented packets * for which we attempt reassembly; * If maxnipq is -1, accept all fragments without limitation. */ if ((nipq > maxnipq) && (maxnipq > 0)) { /* * drop something from the tail of the current queue * before proceeding further */ if (ipq[sum].prev == &ipq[sum]) { /* gak */ for (i = 0; i < IPREASS_NHASH; i++) { if (ipq[i].prev != &ipq[i]) { ip_freef(ipq[i].prev); ipstat.ips_fragtimeout++; break; } } } else { ip_freef(ipq[sum].prev); ipstat.ips_fragtimeout++; } }found: /* * Adjust ip_len to not reflect header, * set ip_mff if more fragments are expected, * convert offset of this to bytes. */ ip->ip_len -= hlen; mff = (ip->ip_off & IP_MF) != 0; if (mff) { /* * Make sure that fragments have a data length * that's a non-zero multiple of 8 bytes. */ if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { ipstat.ips_toosmall++; /* XXX */ goto bad; } m->m_flags |= M_FRAG; } ip->ip_off <<= 3; /* * If datagram marked as having more fragments * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ if (mff || ip->ip_off) { ipstat.ips_fragments++; m->m_pkthdr.header = ip;#ifdef IPDIVERT m = ip_reass(m, fp, &ipq[sum], &divert_info, &divert_cookie);#else m = ip_reass(m, fp, &ipq[sum]);#endif if (m == 0) {#ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL;#endif return; } ipstat.ips_reassembled++; ip = mtod(m, struct ip *); /* Get the header length of the reassembled packet */ hlen = IP_VHL_HL(ip->ip_vhl) << 2;#ifdef IPDIVERT /* Restore original checksum before diverting packet */ if (divert_info != 0) { ip->ip_len += hlen; HTONS(ip->ip_len); HTONS(ip->ip_off); ip->ip_sum = 0; if (hlen == sizeof(struct ip)) ip->ip_sum = in_cksum_hdr(ip); else ip->ip_sum = in_cksum(m, hlen); NTOHS(ip->ip_off); NTOHS(ip->ip_len); ip->ip_len -= hlen; }#endif } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen;#ifdef IPDIVERT /* * Divert or tee packet to the divert protocol if required. * * If divert_info is zero then cookie should be too, so we shouldn't * need to clear them here. Assume divert_packet() does so also. */ if (divert_info != 0) { struct mbuf *clone = NULL; /* Clone packet if we're doing a 'tee' */ if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) clone = m_dup(m, M_DONTWAIT); /* Restore packet header fields to original values */ ip->ip_len += hlen; HTONS(ip->ip_len); HTONS(ip->ip_off); /* Deliver packet to divert input routine */ ip_divert_cookie = divert_cookie; divert_packet(m, 1, divert_info & 0xffff); ipstat.ips_delivered++; /* If 'tee', continue with original packet */ if (clone == NULL) return; m = clone; ip = mtod(m, struct ip *); }#endif#ifdef IPSEC /* * enforce IPsec policy checking if we are seeing last header. * note that we do not visit this with protocols with pcb layer * code - like udp/tcp/raw ip. */ if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && ipsec4_in_reject(m, NULL)) { ipsecstat.in_polvio++; goto bad; }#endif /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; { int off = hlen; (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off);#ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL; /* tcp needed it */#endif return; }bad:#ifdef IPFIREWALL_FORWARD ip_fw_fwd_addr = NULL;#endif m_freem(m);}/* * IP software interrupt routine - to go away sometime soon */static voidipintr(void){ int s; struct mbuf *m; while(1) { s = splimp(); IF_DEQUEUE(&ipintrq, m); splx(s); if (m == 0) return; ip_input(m); }}/* * Take incoming datagram fragment and try to reassemble it into * whole datagram. If a chain for reassembly of this datagram already * exists, then it is given as fp; otherwise have to make a chain. * * When IPDIVERT enabled, keep additional state with each packet that * tells us if we need to divert or tee the packet we're building. */static struct mbuf *#ifdef IPDIVERTip_reass(m, fp, where, divinfo, divcookie)#elseip_reass(m, fp, where)#endif register struct mbuf *m; register struct ipq *fp; struct ipq *where;#ifdef IPDIVERT u_int32_t *divinfo; u_int16_t *divcookie;#endif{ struct ip *ip = mtod(m, struct ip *); register struct mbuf *p = 0, *q, *nq; struct mbuf *t; int hlen = IP_VHL_HL(ip->ip_vhl) << 2; int i, next; /* * Presence of header sizes in mbufs * would confuse code below. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque(fp, where); nipq++; fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; fp->ipq_src = ip->ip_src; fp->ipq_dst = ip->ip_dst; fp->ipq_frags = m; m->m_nextpkt = NULL;#ifdef IPDIVERT fp->ipq_div_info = 0; fp->ipq_div_cookie = 0;#endif goto inserted; }#define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) /* * Find a segment which begins after this one does. */ for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) if (GETIP(q)->ip_off > ip->ip_off) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us, otherwise * stick new segment in the proper place. * * If some of the data is dropped from the the preceding * segment, then it's checksum is invalidated.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?