📄 ip_input.c
字号:
#ifndef lintstatic char *sccsid = "@(#)ip_input.c 4.4 (ULTRIX) 9/11/90";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * 31-Jul-90 jsd * fixes for killer packets with IP options LSR and SRR * * 24-Jul-90 jaw * submitted bug fix for locking problem in ipintr.... * * 16-July-90 U. Sinkewicz * Fix to locking around ip_reass(). * * 7-Jul-90 lp * FDDI performance changes. * * 14-11-89 Ursula Sinkewicz * Removed lk_ifnet and lk_in_ifaddr to coincide with * slip changes. * * 17-Oct-89 Uttam Shikarpur * * Added counter to track the number of bad options for * * network management. (ips_badoptions) * * * * 27-Mar-89 Ursula Sinkewicz * Lowered ipl in lk_rtentry, lk_ifnet, lk_in_ifaddr, exchanged * ip statistics locking for a macro, as per lp changes * made 3/16/89. * * 3-Mar-89 Ursula Sinkewicz * Added support for new directory layout; added pmax * support. * * 13-Feb-89 Ursula Sinkewicz * SMP: Added lk_in_ifaddr and lk_ifnet. * * 15-Jan-88 lp * Merge of final 43BSD changes. Use new memory allocation * scheme for mbufs. * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * * Larry Cohen - 01/17/86 * * - will now accept broadcast of ones or zeros * * * * Marc Teitelbaum and Fred Templin - 08/21/86 * * Added 4.3bsd beta tape enhancements. "ipintr()" now * * handles subet broadcasts and packet forwarding properly.* * (Packets are only forwarded by hosts configured with * * "GATEWAY" option). * ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * @(#)ip_input.c 7.7 (Berkeley) 10/31/87 */#include "../h/param.h"#include "../h/systm.h"#include "../h/mbuf.h"#include "../h/domain.h"#include "../h/protosw.h"#include "../h/socket.h"#include "../h/errno.h"#include "../h/time.h"#include "../h/kernel.h"#include "../h/smp_lock.h"#include "../net/net/if.h"#include "../net/net/route.h"#include "../net/netinet/in.h"#include "../net/netinet/in_pcb.h"#include "../net/netinet/in_systm.h"#include "../net/netinet/in_var.h"#include "../net/netinet/ip.h"#include "../net/netinet/ip_var.h"#include "../net/netinet/ip_icmp.h"#include "../net/netinet/tcp.h"u_char ip_protox[IPPROTO_MAX];int ipqmaxlen = IFQ_MAXLEN;struct in_ifaddr *in_ifaddr; /* first inet address */struct lock_t lk_ipstat; /* SMP: ipstat lock, see ip_var.h */struct lock_t lk_ipq; /* SMP: ip reassembly queue lock *//* * We need to save the IP options in case a protocol wants to respond * to an incoming packet over the same route if the packet got here * using IP source routing. This allows connection establishment and * maintenance when the remote end is on a network that is not known * to us. */int ip_nhops = 0;static struct ip_srcrt { char nop; /* one NOP to align */ char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ struct in_addr route[MAX_IPOPTLEN];} ip_srcrt;extern struct lock_t lk_arptab;/* * 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; pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_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_domain->dom_family == PF_INET && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ip_protox[pr->pr_protocol] = pr - inetsw; /* SMP: Initailize locks here - ipstat, ipq, and ipintrq. 4.22.87.us */ lockinit(&lk_ipq, &lock_ipq_d); lockinit(&lk_ipstat, &lock_ipstat_d); ipq.next = ipq.prev = &ipq; ip_id = time.tv_sec & 0xffff; ipintrq.ifq_maxlen = ipqmaxlen; lockinit(&ipintrq.lk_ifqueue, &lock_ifqueue_d); lockinit(&lk_arptab, &lock_arptab_d);}u_char ipcksum = 1;struct ip *ip_reass();struct sockaddr_in ipaddr = { AF_INET };struct route ipforward_rt;/* * 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(){ register struct ip *ip; register struct mbuf *m; struct mbuf *m0; register int i; register struct ipq *fp; register struct in_ifaddr *ia; struct ifnet *ifp; int hlen, s; /* * This is to keep these long aligned */ struct in_addr dst; struct in_addr src;next: /* * Get next datagram off input queue and get IP header * in first mbuf. */ s = splimp(); /* SMP: Lock element taken off ipintrq along with * next/prev pointers in the queue. 4.22.87.us */ smp_lock(&ipintrq.lk_ifqueue, LK_RETRY); IF_DEQUEUEIF(&ipintrq, m, ifp); smp_unlock(&ipintrq.lk_ifqueue); splx(s); if (m == 0) return; /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. */ if (in_ifaddr == NULL){ goto bad; } IPSTAT(ips_total++); if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && (m = m_pullup(m, sizeof (struct ip))) == 0) { IPSTAT(ips_toosmall++); goto next; } ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ IPSTAT(ips_badhlen++); goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { IPSTAT(ips_badhlen++); goto next; } ip = mtod(m, struct ip *); } if (ipcksum) if (ip->ip_sum = in_cksum(m, hlen)) { IPSTAT(ips_badsum++); goto bad; } /* * Convert fields to host representation. */ ip->ip_len = ntohs((u_short)ip->ip_len); 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 = -(u_short)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 and the original packet to be freed). */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp)) goto next; /* * Check our list of addresses, to see if the packet is for us. */ bcopy(&ip->ip_dst, &dst, sizeof(struct in_addr)); for (ia = in_ifaddr; ia; ia = ia->ia_next) {#define satosin(sa) ((struct sockaddr_in *)(sa)) if (IA_SIN(ia)->sin_addr.s_addr == dst.s_addr) { goto ours; } if (#ifdef DIRECTED_BROADCAST ia->ia_ifp == ifp &&#endif DIRECTED_BROADCAST (ia->ia_ifp->if_flags & IFF_BROADCAST)) { u_long t; if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == dst.s_addr) { goto ours; } if (dst.s_addr == ia->ia_netbroadcast.s_addr) { goto ours; } /* * Look for all-0's host part (old broadcast addr), * either for subnet or net. */ t = ntohl(dst.s_addr); if (t == ia->ia_subnet) { goto ours; } if (t == ia->ia_net) { goto ours; } } } if (dst.s_addr == (u_long)INADDR_BROADCAST) goto ours; if (dst.s_addr == INADDR_ANY) goto ours; /* * Not for us; forward if possible and desirable. */ ip_forwardscreen(ip, ifp); goto next;ours: /* * Look for queue of fragments * of this datagram. */ smp_lock(&lk_ipq, LK_RETRY); if(ipq.next != &ipq) { bcopy(&ip->ip_src, &src, sizeof(struct in_addr)); for (fp = ipq.next; fp != &ipq; fp = fp->next) if (ip->ip_id == fp->ipq_id && src.s_addr == fp->ipq_src.s_addr && 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; ((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) { IPSTAT(ips_fragments++);#ifdef mips /* * if the ip header is not aligned properly, copy the * mbuf to avoid lots of bcopy's later when reassembling * fragments due to placement of fragment pointers within * ip header. */ if (((u_int)ip & 0x3) != 0) { register struct mbuf *mnew; mnew = m_copy(m, 0, m->m_len); mnew->m_next = m_free(m); m = mnew; ip = mtod(m, struct ip *); }#endif mips ip = ip_reass((struct ipasfrag *)ip, fp); smp_unlock(&lk_ipq); if (ip == 0) goto next; m = dtom(ip); } else{ if (fp) { ip_freef(fp); } smp_unlock(&lk_ipq); } /* * Switch out to protocol's input routine. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -