📄 ip_input.c
字号:
//==========================================================================
//
// sys/netinet/ip_input.c
//
//
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-01-10
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
/* $OpenBSD: ip_input.c,v 1.44 1999/12/08 06:50:20 itojun Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
* 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
*/
#include <sys/param.h>
#ifndef __ECOS
#include <sys/systm.h>
#endif
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/kernel.h>
#ifndef __ECOS
#include <sys/syslog.h>
#include <sys/proc.h>
#include <vm/vm.h>
#include <sys/sysctl.h>
#endif
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_ipsp.h>
#ifdef __ECOS
#include <stdio.h> // for 'sprintf()'
#endif
#ifndef IPFORWARDING
#ifdef GATEWAY
#define IPFORWARDING 1 /* forward IP packets not for us */
#else /* GATEWAY */
#define IPFORWARDING 0 /* don't forward IP packets not for us */
#endif /* GATEWAY */
#endif /* IPFORWARDING */
#ifndef IPSENDREDIRECTS
#define IPSENDREDIRECTS 1
#endif
int encdebug = 0;
/*
* Note: DIRECTED_BROADCAST is handled this way so that previous
* configuration using this option will Just Work.
*/
#ifndef IPDIRECTEDBCAST
#ifdef DIRECTED_BROADCAST
#define IPDIRECTEDBCAST 1
#else
#define IPDIRECTEDBCAST 0
#endif /* DIRECTED_BROADCAST */
#endif /* IPDIRECTEDBCAST */
int ipforwarding = IPFORWARDING;
int ipsendredirects = IPSENDREDIRECTS;
int ip_dosourceroute = 0; /* no src-routing unless sysctl'd to enable */
int ip_defttl = IPDEFTTL;
int ip_directedbcast = IPDIRECTEDBCAST;
#ifdef DIAGNOSTIC
int ipprintfs = 0;
#endif
int ipsec_auth_default_level = IPSEC_AUTH_LEVEL_DEFAULT;
int ipsec_esp_trans_default_level = IPSEC_ESP_TRANS_LEVEL_DEFAULT;
int ipsec_esp_network_default_level = IPSEC_ESP_NETWORK_LEVEL_DEFAULT;
/* Keep track of memory used for reassembly */
int ip_maxqueue = 300;
int ip_frags = 0;
/* from in_pcb.c */
extern int ipport_firstauto;
extern int ipport_lastauto;
extern int ipport_hifirstauto;
extern int ipport_hilastauto;
extern struct baddynamicports baddynamicports;
extern struct domain inetdomain;
extern struct protosw inetsw[];
u_char ip_protox[IPPROTO_MAX];
int ipqmaxlen = IFQ_MAXLEN;
struct in_ifaddrhead in_ifaddr;
struct ifqueue ipintrq;
struct ipstat ipstat;
#if defined(IPFILTER) || defined(IPFILTER_LKM)
int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int,
struct mbuf **));
#endif
int ipq_locked;
static __inline int ipq_lock_try __P((void));
static __inline void ipq_unlock __P((void));
static __inline int
ipq_lock_try()
{
int s;
s = splimp();
if (ipq_locked) {
splx(s);
return (0);
}
ipq_locked = 1;
splx(s);
return (1);
}
#define ipq_lock() ipq_lock_try()
static __inline void
ipq_unlock()
{
int s;
s = splimp();
ipq_locked = 0;
splx(s);
}
#if 0 // Now in common layer
static char *ui8tod( cyg_uint8 n, char *p )
{
if( n > 99 ) *p++ = (n/100) + '0';
if( n > 9 ) *p++ = ((n/10)%10) + '0';
*p++ = (n%10) + '0';
return p;
}
char *
inet_ntoa(ina)
struct in_addr ina;
{
static char buf[4*sizeof "123"];
char *p = buf;
unsigned char *ucp = (unsigned char *)&ina;
// sprintf(buf, "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff,
// ucp[2] & 0xff, ucp[3] & 0xff);
p = ui8tod( ucp[0] & 0xFF, p);
*p++ = '.';
p = ui8tod( ucp[1] & 0xFF, p);
*p++ = '.';
p = ui8tod( ucp[2] & 0xFF, p);
*p++ = '.';
p = ui8tod( ucp[3] & 0xFF, p);
*p++ = '\0';
return (buf);
}
#endif
/*
* 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 {
struct in_addr dst; /* final destination */
char nop; /* one NOP to align */
char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */
struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
} ip_srcrt;
static void save_rte __P((u_char *, struct in_addr));
static int ip_weadvertise(u_int32_t);
/*
* IP initialization: fill in IP protocol switch table.
* All protocols not implemented in kernel go to raw IP protocol handler.
*/
void
ip_init()
{
register struct protosw *pr;
register int i;
const u_int16_t defbaddynamicports_tcp[] = DEFBADDYNAMICPORTS_TCP;
const u_int16_t defbaddynamicports_udp[] = DEFBADDYNAMICPORTS_UDP;
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;
LIST_INIT(&ipq);
ipintrq.ifq_maxlen = ipqmaxlen;
TAILQ_INIT(&in_ifaddr);
/* Fill in list of ports not to allocate dynamically. */
bzero((void *)&baddynamicports, sizeof(baddynamicports));
for (i = 0; defbaddynamicports_tcp[i] != 0; i++)
DP_SET(baddynamicports.tcp, defbaddynamicports_tcp[i]);
for (i = 0; defbaddynamicports_udp[i] != 0; i++)
DP_SET(baddynamicports.udp, defbaddynamicports_tcp[i]);
}
struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
struct route ipforward_rt;
void
ipintr()
{
register struct mbuf *m;
int s;
if (needqueuedrain)
m_reclaim();
while (1) {
/*
* Get next datagram off input queue and get IP header
* in first mbuf.
*/
s = splimp();
IF_DEQUEUE(&ipintrq, m);
splx(s);
if (m == 0)
return;
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("ipintr no HDR");
#endif
ipv4_input(m, 0, NULL, 0);
}
}
/*
* Ip input routine. Checksum and byte swap header. If fragmented
* try to reassemble. Process options. Pass to next level.
*/
void
ipv4_input(struct mbuf *m, ...)
{
register struct ip *ip;
register struct ipq *fp;
struct in_ifaddr *ia;
struct ipqent *ipqe;
int hlen, mff;
va_list ap;
int extra;
va_start(ap, m);
extra = va_arg(ap, int);
va_end(ap);
if (extra) {
struct mbuf *newpacket;
if (!(newpacket = m_split(m, extra, M_NOWAIT))) {
m_freem(m);
return;
}
newpacket->m_flags |= m->m_flags;
m_freem(m);
m = newpacket;
extra = 0;
}
/*
* If no IP addresses have been set yet but the interfaces
* are receiving, can't do anything with incoming packets yet.
*/
if (in_ifaddr.tqh_first == 0)
goto bad;
ipstat.ips_total++;
if (m->m_len < sizeof (struct ip) &&
(m = m_pullup(m, sizeof (struct ip))) == 0) {
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)) { /* minimum header length */
ipstat.ips_badhlen++;
goto bad;
}
if (hlen > m->m_len) {
if ((m = m_pullup(m, hlen)) == 0) {
ipstat.ips_badhlen++;
return;
}
ip = mtod(m, struct ip *);
}
if ((ip->ip_sum = in_cksum(m, hlen)) != 0) {
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_pkthdr.len < ip->ip_len) {
ipstat.ips_tooshort++;
goto bad;
}
if (m->m_pkthdr.len > ip->ip_len) {
if (m->m_len == m->m_pkthdr.len) {
m->m_len = ip->ip_len;
m->m_pkthdr.len = ip->ip_len;
} else
m_adj(m, ip->ip_len - m->m_pkthdr.len);
}
#if defined(IPFILTER) || defined(IPFILTER_LKM)
/*
* Check if we want to allow this packet to be processed.
* Consider it to be bad if not.
*/
{
struct mbuf *m0 = m;
if (fr_checkp && (*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m0))
return;
ip = mtod(m = m0, struct ip *);
}
#endif
/*
* 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))
return;
/*
* Check our list of addresses, to see if the packet is for us.
*/
if ((ia = in_iawithaddr(ip->ip_dst, m)) != NULL &&
(ia->ia_ifp->if_flags & IFF_UP))
goto ours;
if (IN_MULTICAST(ip->ip_dst.s_addr)) {
struct in_multi *inm;
#ifdef MROUTING
extern struct socket *ip_mrouter;
if (m->m_flags & M_EXT) {
if ((m = m_pullup(m, hlen)) == 0) {
ipstat.ips_toosmall++;
return;
}
ip = mtod(m, struct ip *);
}
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.
*
* (The IP ident field is put in the same byte order
* as expected when ip_mforward() is called from
* ip_output().)
*/
ip->ip_id = htons(ip->ip_id);
if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
ipstat.ips_cantforward++;
m_freem(m);
return;
}
ip->ip_id = ntohs(ip->ip_id);
/*
* 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++;
}
#endif
/*
* 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_cantforward++;
m_freem(m);
return;
}
goto ours;
}
if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
ip->ip_dst.s_addr == INADDR_ANY)
goto ours;
/*
* Not for us; forward if possible and desirable.
*/
if (ipforwarding == 0) {
ipstat.ips_cantforward++;
m_freem(m);
} else
ip_forward(m, 0);
return;
ours:
/*
* 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_DF | IP_RF)) {
if (m->m_flags & M_EXT) { /* XXX */
if ((m = m_pullup(m, hlen)) == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -