📄 ip_input.c
字号:
/* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp *//* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */#include <slirp.h>#include "ip_icmp.h"int ip_defttl;struct ipstat ipstat;struct ipq ipq;/* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */voidip_init(){ ipq.next = ipq.prev = (ipqp_32)&ipq; ip_id = tt.tv_sec & 0xffff; udp_init(); tcp_init(); ip_defttl = IPDEFTTL;}/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */voidip_input(m) struct mbuf *m;{ register struct ip *ip; int hlen; DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); ipstat.ips_total++; if (m->m_len < sizeof (struct ip)) { ipstat.ips_toosmall++; return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; } hlen = ip->ip_hl << 2; if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */ ipstat.ips_badhlen++; /* or packet too short */ goto bad; } /* keep ip header intact for ICMP reply * ip->ip_sum = cksum(m, hlen); * if (ip->ip_sum) { */ if(cksum(m,hlen)) { ipstat.ips_badsum++; goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { ipstat.ips_tooshort++; goto bad; } /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ if(ip->ip_ttl==0 || ip->ip_ttl==1) { icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; } /* * 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). *//* We do no IP options *//* if (hlen > sizeof (struct ip) && ip_dooptions(m)) * goto next; */ /* * 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.) * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { register struct ipq *fp; /* * Look for queue of fragments * of this datagram. */ for (fp = (struct ipq *) ipq.next; fp != &ipq; fp = (struct ipq *) 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; 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; if (ip->ip_off & IP_MF) ((struct ipasfrag *)ip)->ipf_mff |= 1; else ((struct ipasfrag *)ip)->ipf_mff &= ~1; 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 (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { ipstat.ips_fragments++; ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == 0) return; ipstat.ips_reassembled++; m = dtom(ip); } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; switch (ip->ip_p) { case IPPROTO_TCP: tcp_input(m, hlen, (struct socket *)NULL); break; case IPPROTO_UDP: udp_input(m, hlen); break; case IPPROTO_ICMP: icmp_input(m, hlen); break; default: ipstat.ips_noproto++; m_free(m); } return;bad: m_freem(m); return;}/* * 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. */struct ip *ip_reass(ip, fp) register struct ipasfrag *ip; register struct ipq *fp;{ register struct mbuf *m = dtom(ip); register struct ipasfrag *q; int hlen = ip->ip_hl << 2; int i, next; DEBUG_CALL("ip_reass"); DEBUG_ARG("ip = %lx", (long)ip); DEBUG_ARG("fp = %lx", (long)fp); DEBUG_ARG("m = %lx", (long)m); /* * Presence of header sizes in mbufs * would confuse code below. * Fragment m_data is concatenated. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { struct mbuf *t; if ((t = m_get()) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque_32(fp, &ipq); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; fp->ipq_src = ((struct ip *)ip)->ip_src; fp->ipq_dst = ((struct ip *)ip)->ip_dst; q = (struct ipasfrag *)fp; goto insert; } /* * Find a segment which begins after this one does. */ for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *)q->ipf_next) if (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. */ if (q->ipf_prev != (ipasfragp_32)fp) { i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; m_adj(dtom(ip), i); ip->ip_off += i; ip->ip_len -= i; } } /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { i = (ip->ip_off + ip->ip_len) - q->ip_off; if (i < q->ip_len) { q->ip_len -= i; q->ip_off += i; m_adj(dtom(q), i); break; } q = (struct ipasfrag *) q->ipf_next; m_freem(dtom((struct ipasfrag *) q->ipf_prev)); ip_deq((struct ipasfrag *) q->ipf_prev); }insert: /* * Stick new segment in its place; * check for complete reassembly. */ ip_enq(ip, (struct ipasfrag *) q->ipf_prev); next = 0; for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *) q->ipf_next) { if (q->ip_off != next) return (0); next += q->ip_len; } if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) return (0); /* * Reassembly is complete; concatenate fragments. */ q = (struct ipasfrag *) fp->ipq_next; m = dtom(q); q = (struct ipasfrag *) q->ipf_next; while (q != (struct ipasfrag *)fp) { struct mbuf *t; t = dtom(q); q = (struct ipasfrag *) q->ipf_next; m_cat(m, t); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -