Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.130.2.15 retrieving revision 1.170 diff -u -p -r1.130.2.15 -r1.170 --- src/sys/netinet/ip_input.c 2002/11/11 22:15:23 1.130.2.15 +++ src/sys/netinet/ip_input.c 2003/07/03 05:03:53 1.170 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.130.2.15 2002/11/11 22:15:23 nathanw Exp $ */ +/* $NetBSD: ip_input.c,v 1.170 2003/07/03 05:03:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -102,12 +102,13 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.130.2.15 2002/11/11 22:15:23 nathanw Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.170 2003/07/03 05:03:53 itojun Exp $"); #include "opt_gateway.h" #include "opt_pfil_hooks.h" #include "opt_ipsec.h" #include "opt_mrouting.h" +#include "opt_mbuftrace.h" #include "opt_inet_csum.h" #include @@ -196,6 +197,21 @@ int ip_mtudisc_timeout = IPMTUDISCTIMEOU #ifdef DIAGNOSTIC int ipprintfs = 0; #endif +/* + * XXX - Setting ip_checkinterface mostly implements the receive side of + * the Strong ES model described in RFC 1122, but since the routing table + * and transmit implementation do not implement the Strong ES model, + * setting this to 1 results in an odd hybrid. + * + * XXX - ip_checkinterface currently must be disabled if you use ipnat + * to translate the destination address to another local interface. + * + * XXX - ip_checkinterface must be disabled if you add IP aliases + * to the loopback interface instead of the interface where the + * packets for those addresses are received. + */ +int ip_checkinterface = 0; + struct rttimer_queue *ip_mtudisc_timeout_q = NULL; @@ -205,6 +221,10 @@ u_long in_ifaddrhash; /* size of hash int in_ifaddrentries; /* total number of addrs */ struct in_ifaddrhead in_ifaddr; struct in_ifaddrhashhead *in_ifaddrhashtbl; +u_long in_multihash; /* size of hash table - 1 */ +int in_multientries; /* total number of addrs */ +struct in_multihead in_multi; +struct in_multihashhead *in_multihashtbl; struct ifqueue ipintrq; struct ipstat ipstat; u_int16_t ip_id; @@ -272,6 +292,7 @@ do { \ #define IPQ_UNLOCK() ipq_unlock() +struct pool inmulti_pool; struct pool ipqent_pool; #ifdef INET_CSUM_COUNTERS @@ -309,6 +330,11 @@ static struct ip_srcrt { static void save_rte __P((u_char *, struct in_addr)); +#ifdef MBUFTRACE +struct mowner ip_rx_mowner = { "internet", "rx" }; +struct mowner ip_tx_mowner = { "internet", "tx" }; +#endif + /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. @@ -319,6 +345,8 @@ ip_init() struct protosw *pr; int i; + pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl", + NULL); pool_init(&ipqent_pool, sizeof(struct ipqent), 0, 0, 0, "ipqepl", NULL); @@ -338,6 +366,8 @@ ip_init() TAILQ_INIT(&in_ifaddr); in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IFADDR, M_WAITOK, &in_ifaddrhash); + in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IPMADDR, + M_WAITOK, &in_multihash); ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); #ifdef GATEWAY ipflow_init(); @@ -358,6 +388,11 @@ ip_init() evcnt_attach_static(&ip_hwcsum_ok); evcnt_attach_static(&ip_swcsum); #endif /* INET_CSUM_COUNTERS */ + +#ifdef MBUFTRACE + MOWNER_ATTACH(&ip_tx_mowner); + MOWNER_ATTACH(&ip_rx_mowner); +#endif /* MBUFTRACE */ } struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; @@ -378,6 +413,7 @@ ipintr() splx(s); if (m == 0) return; + MCLAIM(m, &ip_rx_mowner); ip_input(m); } } @@ -396,7 +432,10 @@ ip_input(struct mbuf *m) struct ipqent *ipqe; int hlen = 0, mff, len; int downmatch; + int checkif; + int srcrt = 0; + MCLAIM(m, &ip_rx_mowner); #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("ipintr no HDR"); @@ -411,6 +450,7 @@ ip_input(struct mbuf *m) m->m_flags &= ~M_AUTHIPDGM; } #endif + /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. @@ -551,13 +591,17 @@ ip_input(struct mbuf *m) if (1) #endif { + struct in_addr odst; + + odst = ip->ip_dst; if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, - PFIL_IN) != 0) - return; + PFIL_IN) != 0) + return; if (m == NULL) return; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; + srcrt = (odst.s_addr != ip->ip_dst.s_addr); } #endif /* PFIL_HOOKS */ @@ -580,6 +624,26 @@ ip_input(struct mbuf *m) return; /* + * 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. + * + * 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. + * + * XXX - We need to add a per ifaddr flag for this so that + * we get finer grain control. + */ + checkif = ip_checkinterface && (ipforwarding == 0) && + (m->m_pkthdr.rcvif != NULL) && + ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0); + + /* * Check our list of addresses, to see if the packet is for us. * * Traditional 4.4BSD did not consult IFF_UP at all. @@ -589,6 +653,8 @@ ip_input(struct mbuf *m) downmatch = 0; LIST_FOREACH(ia, &IN_IFADDR_HASH(ip->ip_dst.s_addr), ia_hash) { if (in_hosteq(ia->ia_addr.sin_addr, ip->ip_dst)) { + if (checkif && ia->ia_ifp != m->m_pkthdr.rcvif) + continue; if ((ia->ia_ifp->if_flags & IFF_UP) != 0) break; else @@ -702,7 +768,7 @@ ip_input(struct mbuf *m) } #endif - ip_forward(m, 0); + ip_forward(m, srcrt); } return; @@ -1389,6 +1455,7 @@ ip_srcroute() if (m == 0) return ((struct mbuf *)0); + MCLAIM(m, &inetdomain.dom_mowner); #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ @@ -1509,6 +1576,11 @@ ip_forward(m, srcrt) #endif /* + * We are now in the output path. + */ + MCLAIM(m, &ip_tx_mowner); + + /* * Clear any in-bound checksum flags for this packet. */ m->m_pkthdr.csum_flags = 0; @@ -1654,17 +1726,15 @@ ip_forward(m, srcrt) struct route *ro; sp = ipsec4_getpolicybyaddr(mcopy, - IPSEC_DIR_OUTBOUND, - IP_FORWARDING, - &ipsecerror); + IPSEC_DIR_OUTBOUND, IP_FORWARDING, + &ipsecerror); if (sp == NULL) destifp = ipforward_rt.ro_rt->rt_ifp; else { /* count IPsec header size */ ipsechdr = ipsec4_hdrsiz(mcopy, - IPSEC_DIR_OUTBOUND, - NULL); + IPSEC_DIR_OUTBOUND, NULL); /* * find the correct route for outer IPv4 @@ -1826,13 +1896,8 @@ ip_sysctl(name, namelen, oldp, oldlenp, case IPCTL_MTUDISC: error = sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtudisc); - if (ip_mtudisc != 0 && ip_mtudisc_timeout_q == NULL) { - ip_mtudisc_timeout_q = - rt_timer_queue_create(ip_mtudisc_timeout); - } else if (ip_mtudisc == 0 && ip_mtudisc_timeout_q != NULL) { - rt_timer_queue_destroy(ip_mtudisc_timeout_q, TRUE); - ip_mtudisc_timeout_q = NULL; - } + if (error == 0 && ip_mtudisc == 0) + rt_timer_queue_remove_all(ip_mtudisc_timeout_q, TRUE); return error; case IPCTL_ANONPORTMIN: old = anonportmin; @@ -1868,7 +1933,7 @@ ip_sysctl(name, namelen, oldp, oldlenp, ip_mtudisc_timeout = old; return (EINVAL); } - if (ip_mtudisc_timeout_q != NULL) + if (error == 0) rt_timer_queue_change(ip_mtudisc_timeout_q, ip_mtudisc_timeout); return (error); @@ -1929,6 +1994,9 @@ ip_sysctl(name, namelen, oldp, oldlenp, return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_maxfragpackets)); + case IPCTL_CHECKINTERFACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ip_checkinterface)); default: return (EOPNOTSUPP); }