| version 1.268, 2008/04/24 11:38:37 |
version 1.268.2.5, 2010/03/11 15:04:28 |
|
|
| * 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
* 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 NetBSD |
|
| * Foundation, Inc. and its contributors. |
|
| * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
|
| __KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
| |
|
| #include "opt_inet.h" |
#include "opt_inet.h" |
| |
#include "opt_compat_netbsd.h" |
| #include "opt_gateway.h" |
#include "opt_gateway.h" |
| #include "opt_pfil_hooks.h" |
#include "opt_pfil_hooks.h" |
| #include "opt_ipsec.h" |
#include "opt_ipsec.h" |
| Line 180 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| Line 174 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| #define IPMTUDISCTIMEOUT (10 * 60) /* as per RFC 1191 */ |
#define IPMTUDISCTIMEOUT (10 * 60) /* as per RFC 1191 */ |
| #endif |
#endif |
| |
|
| |
#ifdef COMPAT_50 |
| |
#include <compat/sys/time.h> |
| |
#include <compat/sys/socket.h> |
| |
#endif |
| |
|
| /* |
/* |
| * Note: DIRECTED_BROADCAST is handled this way so that previous |
* Note: DIRECTED_BROADCAST is handled this way so that previous |
| * configuration using this option will Just Work. |
* configuration using this option will Just Work. |
|
|
| |
|
| #define IPQ_UNLOCK() ipq_unlock() |
#define IPQ_UNLOCK() ipq_unlock() |
| |
|
| POOL_INIT(inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl", NULL, |
struct pool inmulti_pool; |
| IPL_SOFTNET); |
struct pool ipqent_pool; |
| POOL_INIT(ipqent_pool, sizeof(struct ipqent), 0, 0, 0, "ipqepl", NULL, |
|
| IPL_VM); |
|
| |
|
| #ifdef INET_CSUM_COUNTERS |
#ifdef INET_CSUM_COUNTERS |
| #include <sys/device.h> |
#include <sys/device.h> |
| Line 386 struct mowner ip_rx_mowner = MOWNER_INIT |
|
| Line 383 struct mowner ip_rx_mowner = MOWNER_INIT |
|
| struct mowner ip_tx_mowner = MOWNER_INIT("internet", "tx"); |
struct mowner ip_tx_mowner = MOWNER_INIT("internet", "tx"); |
| #endif |
#endif |
| |
|
| |
static void sysctl_net_inet_ip_setup(struct sysctllog **); |
| |
|
| /* |
/* |
| * Compute IP limits derived from the value of nmbclusters. |
* Compute IP limits derived from the value of nmbclusters. |
| */ |
*/ |
|
|
| const struct protosw *pr; |
const struct protosw *pr; |
| int i; |
int i; |
| |
|
| |
sysctl_net_inet_ip_setup(NULL); |
| |
|
| |
pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl", |
| |
NULL, IPL_SOFTNET); |
| |
pool_init(&ipqent_pool, sizeof(struct ipqent), 0, 0, 0, "ipqepl", |
| |
NULL, IPL_VM); |
| |
|
| pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); |
pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); |
| if (pr == 0) |
if (pr == 0) |
| panic("ip_init"); |
panic("ip_init"); |
|
|
| ip_nmbclusters_changed(); |
ip_nmbclusters_changed(); |
| |
|
| TAILQ_INIT(&in_ifaddrhead); |
TAILQ_INIT(&in_ifaddrhead); |
| in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IFADDR, |
in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true, |
| M_WAITOK, &in_ifaddrhash); |
&in_ifaddrhash); |
| in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IPMADDR, |
in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true, |
| M_WAITOK, &in_multihash); |
&in_multihash); |
| ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); |
ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); |
| #ifdef GATEWAY |
#ifdef GATEWAY |
| ipflow_init(ip_hashsize); |
ipflow_init(ip_hashsize); |
|
|
| */ |
*/ |
| if (ip->ip_tos != fp->ipq_tos) { |
if (ip->ip_tos != fp->ipq_tos) { |
| IP_STATINC(IP_STAT_BADFRAGS); |
IP_STATINC(IP_STAT_BADFRAGS); |
| |
IPQ_UNLOCK(); |
| goto bad; |
goto bad; |
| } |
} |
| goto found; |
goto found; |
| Line 1125 ip_reass(struct ipqent *ipqe, struct ipq |
|
| Line 1132 ip_reass(struct ipqent *ipqe, struct ipq |
|
| else if (ip_nfragpackets >= ip_maxfragpackets) |
else if (ip_nfragpackets >= ip_maxfragpackets) |
| goto dropfrag; |
goto dropfrag; |
| ip_nfragpackets++; |
ip_nfragpackets++; |
| MALLOC(fp, struct ipq *, sizeof (struct ipq), |
fp = malloc(sizeof (struct ipq), M_FTABLE, M_NOWAIT); |
| M_FTABLE, M_NOWAIT); |
|
| if (fp == NULL) |
if (fp == NULL) |
| goto dropfrag; |
goto dropfrag; |
| LIST_INSERT_HEAD(ipqhead, fp, ipq_q); |
LIST_INSERT_HEAD(ipqhead, fp, ipq_q); |
|
|
| ip->ip_src = fp->ipq_src; |
ip->ip_src = fp->ipq_src; |
| ip->ip_dst = fp->ipq_dst; |
ip->ip_dst = fp->ipq_dst; |
| LIST_REMOVE(fp, ipq_q); |
LIST_REMOVE(fp, ipq_q); |
| FREE(fp, M_FTABLE); |
free(fp, M_FTABLE); |
| ip_nfragpackets--; |
ip_nfragpackets--; |
| m->m_len += (ip->ip_hl << 2); |
m->m_len += (ip->ip_hl << 2); |
| m->m_data -= (ip->ip_hl << 2); |
m->m_data -= (ip->ip_hl << 2); |
| Line 1310 ip_freef(struct ipq *fp) |
|
| Line 1316 ip_freef(struct ipq *fp) |
|
| printf("ip_freef: nfrags %d != %d\n", fp->ipq_nfrags, nfrags); |
printf("ip_freef: nfrags %d != %d\n", fp->ipq_nfrags, nfrags); |
| ip_nfrags -= nfrags; |
ip_nfrags -= nfrags; |
| LIST_REMOVE(fp, ipq_q); |
LIST_REMOVE(fp, ipq_q); |
| FREE(fp, M_FTABLE); |
free(fp, M_FTABLE); |
| ip_nfragpackets--; |
ip_nfragpackets--; |
| } |
} |
| |
|
| Line 1443 ip_slowtimo(void) |
|
| Line 1449 ip_slowtimo(void) |
|
| } |
} |
| |
|
| /* |
/* |
| * Drain off all datagram fragments. |
* Drain off all datagram fragments. Don't acquire softnet_lock as |
| |
* can be called from hardware interrupt context. |
| */ |
*/ |
| void |
void |
| ip_drain(void) |
ip_drain(void) |
| { |
{ |
| |
|
| mutex_enter(softnet_lock); |
|
| KERNEL_LOCK(1, NULL); |
KERNEL_LOCK(1, NULL); |
| |
|
| /* |
/* |
|
|
| } |
} |
| |
|
| KERNEL_UNLOCK_ONE(NULL); |
KERNEL_UNLOCK_ONE(NULL); |
| mutex_exit(softnet_lock); |
|
| } |
} |
| |
|
| /* |
/* |
| Line 1561 ip_dooptions(struct mbuf *m) |
|
| Line 1566 ip_dooptions(struct mbuf *m) |
|
| /* |
/* |
| * locate outgoing interface |
* locate outgoing interface |
| */ |
*/ |
| bcopy((void *)(cp + off), (void *)&ipaddr.sin_addr, |
memcpy((void *)&ipaddr.sin_addr, (void *)(cp + off), |
| sizeof(ipaddr.sin_addr)); |
sizeof(ipaddr.sin_addr)); |
| if (opt == IPOPT_SSRR) |
if (opt == IPOPT_SSRR) |
| ia = ifatoia(ifa_ifwithladdr(sintosa(&ipaddr))); |
ia = ifatoia(ifa_ifwithladdr(sintosa(&ipaddr))); |
| Line 1597 ip_dooptions(struct mbuf *m) |
|
| Line 1602 ip_dooptions(struct mbuf *m) |
|
| off--; /* 0 origin */ |
off--; /* 0 origin */ |
| if ((off + sizeof(struct in_addr)) > optlen) |
if ((off + sizeof(struct in_addr)) > optlen) |
| break; |
break; |
| bcopy((void *)(&ip->ip_dst), (void *)&ipaddr.sin_addr, |
memcpy((void *)&ipaddr.sin_addr, (void *)(&ip->ip_dst), |
| sizeof(ipaddr.sin_addr)); |
sizeof(ipaddr.sin_addr)); |
| /* |
/* |
| * locate outgoing interface; if we're the destination, |
* locate outgoing interface; if we're the destination, |
| Line 1664 ip_dooptions(struct mbuf *m) |
|
| Line 1669 ip_dooptions(struct mbuf *m) |
|
| (u_char *)ip; |
(u_char *)ip; |
| goto bad; |
goto bad; |
| } |
} |
| bcopy(cp0, &ipaddr.sin_addr, |
memcpy(&ipaddr.sin_addr, cp0, |
| sizeof(struct in_addr)); |
sizeof(struct in_addr)); |
| if (ifatoia(ifa_ifwithaddr(sintosa(&ipaddr))) |
if (ifatoia(ifa_ifwithaddr(sintosa(&ipaddr))) |
| == NULL) |
== NULL) |
| Line 1738 save_rte(u_char *option, struct in_addr |
|
| Line 1743 save_rte(u_char *option, struct in_addr |
|
| #endif /* 0 */ |
#endif /* 0 */ |
| if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) |
if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) |
| return; |
return; |
| bcopy((void *)option, (void *)ip_srcrt.srcopt, olen); |
memcpy((void *)ip_srcrt.srcopt, (void *)option, olen); |
| ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); |
ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); |
| ip_srcrt.dst = dst; |
ip_srcrt.dst = dst; |
| } |
} |
| Line 1975 ip_forward(struct mbuf *m, int srcrt) |
|
| Line 1980 ip_forward(struct mbuf *m, int srcrt) |
|
| type = ICMP_UNREACH; |
type = ICMP_UNREACH; |
| code = ICMP_UNREACH_NEEDFRAG; |
code = ICMP_UNREACH_NEEDFRAG; |
| |
|
| if ((rt = rtcache_validate(&ipforward_rt)) != NULL) { |
if ((rt = rtcache_validate(&ipforward_rt)) != NULL) |
| |
destmtu = rt->rt_ifp->if_mtu; |
| |
|
| #if defined(IPSEC) || defined(FAST_IPSEC) |
#if defined(IPSEC) || defined(FAST_IPSEC) |
| |
{ |
| /* |
/* |
| * If the packet is routed over IPsec tunnel, tell the |
* If the packet is routed over IPsec tunnel, tell the |
| * originator the tunnel MTU. |
* originator the tunnel MTU. |
| Line 1993 ip_forward(struct mbuf *m, int srcrt) |
|
| Line 2000 ip_forward(struct mbuf *m, int srcrt) |
|
| sp = ipsec4_getpolicybyaddr(mcopy, |
sp = ipsec4_getpolicybyaddr(mcopy, |
| IPSEC_DIR_OUTBOUND, IP_FORWARDING, |
IPSEC_DIR_OUTBOUND, IP_FORWARDING, |
| &ipsecerror); |
&ipsecerror); |
| #endif |
|
| |
|
| destmtu = rt->rt_ifp->if_mtu; |
|
| #if defined(IPSEC) || defined(FAST_IPSEC) |
|
| if (sp != NULL) { |
if (sp != NULL) { |
| /* count IPsec header size */ |
/* count IPsec header size */ |
| ipsechdr = ipsec4_hdrsiz(mcopy, |
ipsechdr = ipsec4_hdrsiz(mcopy, |
| Line 2011 ip_forward(struct mbuf *m, int srcrt) |
|
| Line 2015 ip_forward(struct mbuf *m, int srcrt) |
|
| && sp->req->sav != NULL |
&& sp->req->sav != NULL |
| && sp->req->sav->sah != NULL) { |
&& sp->req->sav->sah != NULL) { |
| ro = &sp->req->sav->sah->sa_route; |
ro = &sp->req->sav->sah->sa_route; |
| |
rt = rtcache_validate(ro); |
| if (rt && rt->rt_ifp) { |
if (rt && rt->rt_ifp) { |
| destmtu = |
destmtu = |
| rt->rt_rmx.rmx_mtu ? |
rt->rt_rmx.rmx_mtu ? |
| Line 2026 ip_forward(struct mbuf *m, int srcrt) |
|
| Line 2031 ip_forward(struct mbuf *m, int srcrt) |
|
| KEY_FREESP(&sp); |
KEY_FREESP(&sp); |
| #endif |
#endif |
| } |
} |
| #endif /*defined(IPSEC) || defined(FAST_IPSEC)*/ |
|
| } |
} |
| |
#endif /*defined(IPSEC) || defined(FAST_IPSEC)*/ |
| IP_STATINC(IP_STAT_CANTFRAG); |
IP_STATINC(IP_STAT_CANTFRAG); |
| break; |
break; |
| |
|
| Line 2056 ip_savecontrol(struct inpcb *inp, struct |
|
| Line 2061 ip_savecontrol(struct inpcb *inp, struct |
|
| struct mbuf *m) |
struct mbuf *m) |
| { |
{ |
| |
|
| if (inp->inp_socket->so_options & SO_TIMESTAMP) { |
if (inp->inp_socket->so_options & SO_TIMESTAMP |
| |
#ifdef SO_OTIMESTAMP |
| |
|| inp->inp_socket->so_options & SO_OTIMESTAMP |
| |
#endif |
| |
) { |
| struct timeval tv; |
struct timeval tv; |
| |
|
| microtime(&tv); |
microtime(&tv); |
| |
#ifdef SO_OTIMESTAMP |
| |
if (inp->inp_socket->so_options & SO_OTIMESTAMP) { |
| |
struct timeval50 tv50; |
| |
timeval_to_timeval50(&tv, &tv50); |
| |
*mp = sbcreatecontrol((void *) &tv50, sizeof(tv50), |
| |
SCM_OTIMESTAMP, SOL_SOCKET); |
| |
} else |
| |
#endif |
| *mp = sbcreatecontrol((void *) &tv, sizeof(tv), |
*mp = sbcreatecontrol((void *) &tv, sizeof(tv), |
| SCM_TIMESTAMP, SOL_SOCKET); |
SCM_TIMESTAMP, SOL_SOCKET); |
| if (*mp) |
if (*mp) |
| Line 2105 ip_savecontrol(struct inpcb *inp, struct |
|
| Line 2122 ip_savecontrol(struct inpcb *inp, struct |
|
| if (*mp) |
if (*mp) |
| mp = &(*mp)->m_next; |
mp = &(*mp)->m_next; |
| } |
} |
| |
if (inp->inp_flags & INP_RECVTTL) { |
| |
*mp = sbcreatecontrol((void *) &ip->ip_ttl, |
| |
sizeof(uint8_t), IP_RECVTTL, IPPROTO_IP); |
| |
if (*mp) |
| |
mp = &(*mp)->m_next; |
| |
} |
| } |
} |
| |
|
| /* |
/* |
| Line 2123 sysctl_net_inet_ip_forwsrcrt(SYSCTLFN_AR |
|
| Line 2146 sysctl_net_inet_ip_forwsrcrt(SYSCTLFN_AR |
|
| if (error || newp == NULL) |
if (error || newp == NULL) |
| return (error); |
return (error); |
| |
|
| if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FORWSRCRT, |
error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FORWSRCRT, |
| 0, NULL, NULL, NULL)) |
0, NULL, NULL, NULL); |
| return (EPERM); |
if (error) |
| |
return (error); |
| |
|
| ip_forwsrcrt = tmp; |
ip_forwsrcrt = tmp; |
| |
|
| Line 2151 sysctl_net_inet_ip_pmtudto(SYSCTLFN_ARGS |
|
| Line 2175 sysctl_net_inet_ip_pmtudto(SYSCTLFN_ARGS |
|
| if (tmp < 0) |
if (tmp < 0) |
| return (EINVAL); |
return (EINVAL); |
| |
|
| |
mutex_enter(softnet_lock); |
| |
|
| ip_mtudisc_timeout = tmp; |
ip_mtudisc_timeout = tmp; |
| rt_timer_queue_change(ip_mtudisc_timeout_q, ip_mtudisc_timeout); |
rt_timer_queue_change(ip_mtudisc_timeout_q, ip_mtudisc_timeout); |
| |
|
| |
mutex_exit(softnet_lock); |
| |
|
| return (0); |
return (0); |
| } |
} |
| |
|
| Line 2164 sysctl_net_inet_ip_pmtudto(SYSCTLFN_ARGS |
|
| Line 2192 sysctl_net_inet_ip_pmtudto(SYSCTLFN_ARGS |
|
| static int |
static int |
| sysctl_net_inet_ip_maxflows(SYSCTLFN_ARGS) |
sysctl_net_inet_ip_maxflows(SYSCTLFN_ARGS) |
| { |
{ |
| int s; |
int error; |
| |
|
| s = sysctl_lookup(SYSCTLFN_CALL(rnode)); |
error = sysctl_lookup(SYSCTLFN_CALL(rnode)); |
| if (s || newp == NULL) |
if (error || newp == NULL) |
| return (s); |
return (error); |
| |
|
| |
mutex_enter(softnet_lock); |
| |
KERNEL_LOCK(1, NULL); |
| |
|
| s = splsoftnet(); |
|
| ipflow_prune(); |
ipflow_prune(); |
| splx(s); |
|
| |
KERNEL_UNLOCK_ONE(NULL); |
| |
mutex_exit(softnet_lock); |
| |
|
| return (0); |
return (0); |
| } |
} |
| |
|
| static int |
static int |
| sysctl_net_inet_ip_hashsize(SYSCTLFN_ARGS) |
sysctl_net_inet_ip_hashsize(SYSCTLFN_ARGS) |
| { |
{ |
| int error, tmp; |
int error, tmp; |
| struct sysctlnode node; |
struct sysctlnode node; |
| |
|
| Line 2194 sysctl_net_inet_ip_hashsize(SYSCTLFN_ARG |
|
| Line 2226 sysctl_net_inet_ip_hashsize(SYSCTLFN_ARG |
|
| /* |
/* |
| * Can only fail due to malloc() |
* Can only fail due to malloc() |
| */ |
*/ |
| if (ipflow_invalidate_all(tmp)) |
mutex_enter(softnet_lock); |
| return ENOMEM; |
KERNEL_LOCK(1, NULL); |
| |
|
| |
error = ipflow_invalidate_all(tmp); |
| |
|
| |
KERNEL_UNLOCK_ONE(NULL); |
| |
mutex_exit(softnet_lock); |
| |
|
| } else { |
} else { |
| /* |
/* |
| * EINVAL if not a power of 2 |
* EINVAL if not a power of 2 |
| */ |
*/ |
| return EINVAL; |
error = EINVAL; |
| } |
} |
| |
|
| return (0); |
return error; |
| } |
} |
| #endif /* GATEWAY */ |
#endif /* GATEWAY */ |
| |
|
| static int |
static int |
| sysctl_net_inet_ip_stats(SYSCTLFN_ARGS) |
sysctl_net_inet_ip_stats(SYSCTLFN_ARGS) |
| { |
{ |
| netstat_sysctl_context ctx; |
|
| uint64_t ips[IP_NSTATS]; |
|
| |
|
| ctx.ctx_stat = ipstat_percpu; |
return (NETSTAT_SYSCTL(ipstat_percpu, IP_NSTATS)); |
| ctx.ctx_counters = ips; |
|
| ctx.ctx_ncounters = IP_NSTATS; |
|
| return (NETSTAT_SYSCTL(&ctx)); |
|
| } |
} |
| |
|
| SYSCTL_SETUP(sysctl_net_inet_ip_setup, "sysctl net.inet.ip subtree setup") |
static void |
| |
sysctl_net_inet_ip_setup(struct sysctllog **clog) |
| { |
{ |
| extern int subnetsarelocal, hostzeroisbroadcast; |
extern int subnetsarelocal, hostzeroisbroadcast; |
| |
|