ip_input.c
来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 811 行 · 第 1/2 页
C
811 行
#ifndef lintstatic char sccsid[] = "@(#)ip_input.c 1.1 92/07/30 Copyr 1986 Sun Micro";#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. */#include <sys/param.h>#include "boot/systm.h"#include <sys/mbuf.h>#include "boot/domain.h"#include "boot/protosw.h"#include <sys/socket.h>#include <sys/errno.h>#include <sys/time.h>#include <sys/kernel.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_pcb.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_var.h>#include <netinet/ip_icmp.h>#include <netinet/tcp.h>#include <mon/sunromvec.h>u_char ip_protox[IPPROTO_MAX];int ipqmaxlen = IFQ_MAXLEN;struct ifnet *ifinet; /* first inet interface */int ip_gotit = 0;int ip_reasstot = 0;static int dump_debug = 30;#undef IPFRAGTTL#define IPFRAGTTL 8#define MAXTRACE 128struct { int ip_ident; int ip_time; int ip_diff; int ip_offset;} ip_trace[MAXTRACE];int ip_trace_index = MAXTRACE-1;#define NEXT_TRACE(i) (i=((i)==(MAXTRACE-1)?0:i+1))#ifdef OPENPROMS#define millitime() prom_gettime()#else#define millitime() (*romp->v_nmiclock)#endif !OPENPROMS/* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ip_init(){ register struct protosw *pr; register int i; struct ifnet *if_ifwithaf(); pr = pffindproto(PF_INET, IPPROTO_RAW); if (pr == 0) panic("ip_init"); for (i = 0; i < IPPROTO_MAX; i++) ip_protox[i] = pr - inetsw; for (pr = inetdomain.dom_protosw; pr < inetdomain.dom_protoswNPROTOSW; pr++) { if (pr->pr_family == PF_INET && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { ip_protox[pr->pr_protocol] = pr - inetsw; } } ipq.next = ipq.prev = &ipq; ip_id = time.tv_sec & 0xffff; ifinet = if_ifwithaf(AF_INET);}u_char i_ipcksum = 1;struct ip *ip_reass();struct sockaddr_in ipaddr = { AF_INET };/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassamble. If complete and fragment queue exists, discard. * Process options. Pass to next level. */ipintr(m) struct mbuf *m;{ register struct ip *ip; struct mbuf *m0; register int i; register struct ipq *fp; int hlen; register struct ifaddr *ifa;#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ipintr(m 0x%x) type 0x%x\n", m, m->m_type);#endif /* DUMP_DEBUG */ ip_gotit = 0; /* * Get next datagram off input queue and get IP header * in first mbuf. */ if (m == 0) { dprint(dump_debug, 0, "ipintr: NULL mbuf\n"); return; } if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && (m = m_pullup(m, sizeof (struct ip))) == 0) { dprint(dump_debug, 0, "ipintr: mbuff too small\n"); ipstat.ips_toosmall++; return; } ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; if (hlen < 10) { /* minimum header length */ dprint(dump_debug, 0, "ipintr: bad hl 0x%x\n", hlen); ipstat.ips_badhlen++; m_freem(m); return; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { dprint(dump_debug, 0, "ipintr: bad pullup\n"); ipstat.ips_badhlen++; return; } ip = mtod(m, struct ip *); } if (i_ipcksum) if (ip->ip_sum = ipcksum((caddr_t)ip, (unsigned short)hlen)) { dprint(dump_debug, 0, "ipintr: ip_sum 0x%x\n", ip->ip_sum); ipstat.ips_badsum++; goto bad; } /* * Convert fields to host representation. */ ip->ip_len = ntohs((u_short)ip->ip_len);#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ipintr: ip_len 0x%x\n", ip->ip_len);#endif if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } ip->ip_id = ntohs(ip->ip_id); ip->ip_off = ntohs((u_short)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. */ i = -ip->ip_len; m0 = m; for (;;) { i += m->m_len; if (m->m_next == 0) break; m = m->m_next; } if (i != 0) { if (i < 0) { ipstat.ips_tooshort++; m = m0; goto bad; } if (i <= m->m_len) m->m_len -= i; else m_adj(m0, -i); } m = m0; /* * 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). */ if (hlen > sizeof (struct ip) && ip_dooptions(ip)) return; /* * Fast check on the first internet * interface in the list. */ if (ifinet) { struct sockaddr_in *sin; ifa = ifinet->if_addrlist; sin = (struct sockaddr_in *)&ifa->ifa_addr; if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if ((ifinet->if_flags & IFF_BROADCAST) && ip->ip_dst.s_addr == INADDR_ANY) goto ours; } ipaddr.sin_addr = ip->ip_dst; if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0 && (*(int *)&ip->ip_dst) != -1) { ip_forward(ip); return; }ours: /* * Look for queue of fragments * of this datagram. */ for (fp = ipq.next; fp != &ipq; 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;found: ip_trace[NEXT_TRACE(ip_trace_index)].ip_ident = ip->ip_id; ip_trace[ip_trace_index].ip_time = millitime(); ip_trace[ip_trace_index].ip_diff = ip_trace[ip_trace_index].ip_time - ip_trace[ip_trace_index-1].ip_time; ip_trace[ip_trace_index].ip_offset = ip->ip_off; /* * 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; ((struct ipasfrag *)ip)->ipf_mff = 0; if (ip->ip_off & IP_MF) ((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 || ip->ip_off) { ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == 0) { return; } hlen = ip->ip_hl << 2; m = dtom(ip); } else if (fp) ip_freef(fp); ip_gotit = 1; /* * Switch out to protocol's input routine. */ (*inetsw[ip_protox[ip->ip_p]].pr_input)(m); return;bad: dprint(dump_debug, 0, "ipintr: bad\n"); 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; struct mbuf *t; int hlen = ip->ip_hl << 2; int i, next;#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ip_reass(ip 0x%x fp 0x%x)\n", ip, fp);#endif /* DUMP_DEBUG */ /* * Presence of header sizes in mbufs * would confuse code below. */ m->m_off += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *);#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ip_reass: t 0x%x fp 0x%x type 0x%x\n", t, fp, t->m_type);#endif /* DUMP_DEBUG */ insque(fp, &ipq); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)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 = fp->ipq_next; q != (struct ipasfrag *)fp; q = 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 != (struct ipasfrag *)fp) { i = q->ipf_prev->ip_off + 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 = q->ipf_next; m_freem(dtom(q->ipf_prev)); ip_deq(q->ipf_prev); }insert: /* * Stick new segment in its place; * check for complete reassembly. */ ip_enq(ip, q->ipf_prev); next = 0; for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { if (q->ip_off != next) return (0); next += q->ip_len; } if (q->ipf_prev->ipf_mff) return (0); /* * Reassembly is complete; concatenate fragments. */ q = fp->ipq_next; m = dtom(q); t = m->m_next; m->m_next = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?